1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 1999 The Apache Software Foundation. All rights
  6. * reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The end-user documentation included with the redistribution,
  21. * if any, must include the following acknowledgment:
  22. * "This product includes software developed by the
  23. * Apache Software Foundation (http://www.apache.org/)."
  24. * Alternately, this acknowledgment may appear in the software itself,
  25. * if and wherever such third-party acknowledgments normally appear.
  26. *
  27. * 4. The names "Xalan" and "Apache Software Foundation" must
  28. * not be used to endorse or promote products derived from this
  29. * software without prior written permission. For written
  30. * permission, please contact apache@apache.org.
  31. *
  32. * 5. Products derived from this software may not be called "Apache",
  33. * nor may "Apache" appear in their name, without prior written
  34. * permission of the Apache Software Foundation.
  35. *
  36. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  37. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  38. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  40. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  43. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  44. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  45. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  46. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47. * SUCH DAMAGE.
  48. * ====================================================================
  49. *
  50. * This software consists of voluntary contributions made by many
  51. * individuals on behalf of the Apache Software Foundation and was
  52. * originally based on software copyright (c) 1999, Lotus
  53. * Development Corporation., http://www.lotus.com. For more
  54. * information on the Apache Software Foundation, please see
  55. * <http://www.apache.org/>.
  56. */
  57. package org.apache.xml.utils;
  58. import java.util.EmptyStackException;
  59. import java.util.Enumeration;
  60. import java.util.Hashtable;
  61. import java.util.Vector;
  62. /**
  63. * Encapsulate Namespace tracking logic for use by SAX drivers.
  64. *
  65. * <p>This class is an attempt to rewrite the SAX NamespaceSupport
  66. * "helper" class for improved efficiency. It can be used to track the
  67. * namespace declarations currently in scope, providing lookup
  68. * routines to map prefixes to URIs and vice versa.</p>
  69. *
  70. * <p>ISSUE: For testing purposes, I've extended NamespaceSupport even
  71. * though I'm completely reasserting all behaviors and fields.
  72. * Wasteful.... But SAX did not put an interface under that object and
  73. * we seem to have written that SAX class into our APIs... and I don't
  74. * want to argue with it right now. </p>
  75. *
  76. * @see org.xml.sax.helpers.NamespaceSupport
  77. * */
  78. public class NamespaceSupport2
  79. extends org.xml.sax.helpers.NamespaceSupport
  80. {
  81. ////////////////////////////////////////////////////////////////////
  82. // Internal state.
  83. ////////////////////////////////////////////////////////////////////
  84. private Context2 currentContext; // Current point on the double-linked stack
  85. ////////////////////////////////////////////////////////////////////
  86. // Constants.
  87. ////////////////////////////////////////////////////////////////////
  88. /**
  89. * The XML Namespace as a constant.
  90. *
  91. * <p>This is the Namespace URI that is automatically mapped
  92. * to the "xml" prefix.</p>
  93. */
  94. public final static String XMLNS =
  95. "http://www.w3.org/XML/1998/namespace";
  96. ////////////////////////////////////////////////////////////////////
  97. // Constructor.
  98. ////////////////////////////////////////////////////////////////////
  99. /**
  100. * Create a new Namespace support object.
  101. */
  102. public NamespaceSupport2 ()
  103. {
  104. reset();
  105. }
  106. ////////////////////////////////////////////////////////////////////
  107. // Context management.
  108. ////////////////////////////////////////////////////////////////////
  109. /**
  110. * Reset this Namespace support object for reuse.
  111. *
  112. * <p>It is necessary to invoke this method before reusing the
  113. * Namespace support object for a new session.</p>
  114. */
  115. public void reset ()
  116. {
  117. // Discarding the whole stack doesn't save us a lot versus
  118. // creating a new NamespaceSupport. Do we care, or should we
  119. // change this to just reset the root context?
  120. currentContext = new Context2(null);
  121. currentContext.declarePrefix("xml", XMLNS);
  122. }
  123. /**
  124. * Start a new Namespace context.
  125. *
  126. * <p>Normally, you should push a new context at the beginning
  127. * of each XML element: the new context will automatically inherit
  128. * the declarations of its parent context, but it will also keep
  129. * track of which declarations were made within this context.</p>
  130. *
  131. * <p>The Namespace support object always starts with a base context
  132. * already in force: in this context, only the "xml" prefix is
  133. * declared.</p>
  134. *
  135. * @see #popContext
  136. */
  137. public void pushContext ()
  138. {
  139. // JJK: Context has a parent pointer.
  140. // That means we don't need a stack to pop.
  141. // We may want to retain for reuse, but that can be done via
  142. // a child pointer.
  143. Context2 parentContext=currentContext;
  144. currentContext = parentContext.getChild();
  145. if (currentContext == null){
  146. currentContext = new Context2(parentContext);
  147. }
  148. else{
  149. // JJK: This will wipe out any leftover data
  150. // if we're reusing a previously allocated Context.
  151. currentContext.setParent(parentContext);
  152. }
  153. }
  154. /**
  155. * Revert to the previous Namespace context.
  156. *
  157. * <p>Normally, you should pop the context at the end of each
  158. * XML element. After popping the context, all Namespace prefix
  159. * mappings that were previously in force are restored.</p>
  160. *
  161. * <p>You must not attempt to declare additional Namespace
  162. * prefixes after popping a context, unless you push another
  163. * context first.</p>
  164. *
  165. * @see #pushContext
  166. */
  167. public void popContext ()
  168. {
  169. Context2 parentContext=currentContext.getParent();
  170. if(parentContext==null)
  171. throw new EmptyStackException();
  172. else
  173. currentContext = parentContext;
  174. }
  175. ////////////////////////////////////////////////////////////////////
  176. // Operations within a context.
  177. ////////////////////////////////////////////////////////////////////
  178. /**
  179. * Declare a Namespace prefix.
  180. *
  181. * <p>This method declares a prefix in the current Namespace
  182. * context; the prefix will remain in force until this context
  183. * is popped, unless it is shadowed in a descendant context.</p>
  184. *
  185. * <p>To declare a default Namespace, use the empty string. The
  186. * prefix must not be "xml" or "xmlns".</p>
  187. *
  188. * <p>Note that you must <em>not</em> declare a prefix after
  189. * you've pushed and popped another Namespace.</p>
  190. *
  191. * <p>Note that there is an asymmetry in this library: while {@link
  192. * #getPrefix getPrefix} will not return the default "" prefix,
  193. * even if you have declared one; to check for a default prefix,
  194. * you have to look it up explicitly using {@link #getURI getURI}.
  195. * This asymmetry exists to make it easier to look up prefixes
  196. * for attribute names, where the default prefix is not allowed.</p>
  197. *
  198. * @param prefix The prefix to declare, or null for the empty
  199. * string.
  200. * @param uri The Namespace URI to associate with the prefix.
  201. * @return true if the prefix was legal, false otherwise
  202. * @see #processName
  203. * @see #getURI
  204. * @see #getPrefix
  205. */
  206. public boolean declarePrefix (String prefix, String uri)
  207. {
  208. if (prefix.equals("xml") || prefix.equals("xmlns")) {
  209. return false;
  210. } else {
  211. currentContext.declarePrefix(prefix, uri);
  212. return true;
  213. }
  214. }
  215. /**
  216. * Process a raw XML 1.0 name.
  217. *
  218. * <p>This method processes a raw XML 1.0 name in the current
  219. * context by removing the prefix and looking it up among the
  220. * prefixes currently declared. The return value will be the
  221. * array supplied by the caller, filled in as follows:</p>
  222. *
  223. * <dl>
  224. * <dt>parts[0]</dt>
  225. * <dd>The Namespace URI, or an empty string if none is
  226. * in use.</dd>
  227. * <dt>parts[1]</dt>
  228. * <dd>The local name (without prefix).</dd>
  229. * <dt>parts[2]</dt>
  230. * <dd>The original raw name.</dd>
  231. * </dl>
  232. *
  233. * <p>All of the strings in the array will be internalized. If
  234. * the raw name has a prefix that has not been declared, then
  235. * the return value will be null.</p>
  236. *
  237. * <p>Note that attribute names are processed differently than
  238. * element names: an unprefixed element name will received the
  239. * default Namespace (if any), while an unprefixed element name
  240. * will not.</p>
  241. *
  242. * @param qName The raw XML 1.0 name to be processed.
  243. * @param parts A string array supplied by the caller, capable of
  244. * holding at least three members.
  245. * @param isAttribute A flag indicating whether this is an
  246. * attribute name (true) or an element name (false).
  247. * @return The supplied array holding three internalized strings
  248. * representing the Namespace URI (or empty string), the
  249. * local name, and the raw XML 1.0 name; or null if there
  250. * is an undeclared prefix.
  251. * @see #declarePrefix
  252. * @see java.lang.String#intern */
  253. public String [] processName (String qName, String[] parts,
  254. boolean isAttribute)
  255. {
  256. String[] name=currentContext.processName(qName, isAttribute);
  257. if(name==null)
  258. return null;
  259. // JJK: This recopying is required because processName may return
  260. // a cached result. I Don't Like It. *****
  261. System.arraycopy(name,0,parts,0,3);
  262. return parts;
  263. }
  264. /**
  265. * Look up a prefix and get the currently-mapped Namespace URI.
  266. *
  267. * <p>This method looks up the prefix in the current context.
  268. * Use the empty string ("") for the default Namespace.</p>
  269. *
  270. * @param prefix The prefix to look up.
  271. * @return The associated Namespace URI, or null if the prefix
  272. * is undeclared in this context.
  273. * @see #getPrefix
  274. * @see #getPrefixes
  275. */
  276. public String getURI (String prefix)
  277. {
  278. return currentContext.getURI(prefix);
  279. }
  280. /**
  281. * Return an enumeration of all prefixes currently declared.
  282. *
  283. * <p><strong>Note:</strong> if there is a default prefix, it will not be
  284. * returned in this enumeration; check for the default prefix
  285. * using the {@link #getURI getURI} with an argument of "".</p>
  286. *
  287. * @return An enumeration of all prefixes declared in the
  288. * current context except for the empty (default)
  289. * prefix.
  290. * @see #getDeclaredPrefixes
  291. * @see #getURI
  292. */
  293. public Enumeration getPrefixes ()
  294. {
  295. return currentContext.getPrefixes();
  296. }
  297. /**
  298. * Return one of the prefixes mapped to a Namespace URI.
  299. *
  300. * <p>If more than one prefix is currently mapped to the same
  301. * URI, this method will make an arbitrary selection; if you
  302. * want all of the prefixes, use the {@link #getPrefixes}
  303. * method instead.</p>
  304. *
  305. * <p><strong>Note:</strong> this will never return the empty
  306. * (default) prefix; to check for a default prefix, use the {@link
  307. * #getURI getURI} method with an argument of "".</p>
  308. *
  309. * @param uri The Namespace URI.
  310. * @return One of the prefixes currently mapped to the URI supplied,
  311. * or null if none is mapped or if the URI is assigned to
  312. * the default Namespace.
  313. * @see #getPrefixes(java.lang.String)
  314. * @see #getURI */
  315. public String getPrefix (String uri)
  316. {
  317. return currentContext.getPrefix(uri);
  318. }
  319. /**
  320. * Return an enumeration of all prefixes currently declared for a URI.
  321. *
  322. * <p>This method returns prefixes mapped to a specific Namespace
  323. * URI. The xml: prefix will be included. If you want only one
  324. * prefix that's mapped to the Namespace URI, and you don't care
  325. * which one you get, use the {@link #getPrefix getPrefix}
  326. * method instead.</p>
  327. *
  328. * <p><strong>Note:</strong> the empty (default) prefix is
  329. * <em>never</em> included in this enumeration; to check for the
  330. * presence of a default Namespace, use the {@link #getURI getURI}
  331. * method with an argument of "".</p>
  332. *
  333. * @param uri The Namespace URI.
  334. * @return An enumeration of all prefixes declared in the
  335. * current context.
  336. * @see #getPrefix
  337. * @see #getDeclaredPrefixes
  338. * @see #getURI */
  339. public Enumeration getPrefixes (String uri)
  340. {
  341. // JJK: The old code involved creating a vector, filling it
  342. // with all the matching prefixes, and then getting its
  343. // elements enumerator. Wastes storage, wastes cycles if we
  344. // don't actually need them all. Better to either implement
  345. // a specific enumerator for these prefixes... or a filter
  346. // around the all-prefixes enumerator, which comes out to
  347. // roughly the same thing.
  348. //
  349. // **** Currently a filter. That may not be most efficient
  350. // when I'm done restructuring storage!
  351. return new PrefixForUriEnumerator(this,uri,getPrefixes());
  352. }
  353. /**
  354. * Return an enumeration of all prefixes declared in this context.
  355. *
  356. * <p>The empty (default) prefix will be included in this
  357. * enumeration; note that this behaviour differs from that of
  358. * {@link #getPrefix} and {@link #getPrefixes}.</p>
  359. *
  360. * @return An enumeration of all prefixes declared in this
  361. * context.
  362. * @see #getPrefixes
  363. * @see #getURI
  364. */
  365. public Enumeration getDeclaredPrefixes ()
  366. {
  367. return currentContext.getDeclaredPrefixes();
  368. }
  369. }
  370. ////////////////////////////////////////////////////////////////////
  371. // Local classes.
  372. // These were _internal_ classes... but in fact they don't have to be,
  373. // and may be more efficient if they aren't.
  374. ////////////////////////////////////////////////////////////////////
  375. /**
  376. * Implementation of Enumeration filter, wrapped
  377. * aroung the get-all-prefixes version of the operation. This is NOT
  378. * necessarily the most efficient approach; finding the URI and then asking
  379. * what prefixes apply to it might make much more sense.
  380. */
  381. class PrefixForUriEnumerator implements Enumeration
  382. {
  383. private Enumeration allPrefixes;
  384. private String uri;
  385. private String lookahead=null;
  386. private NamespaceSupport2 nsup;
  387. // Kluge: Since one can't do a constructor on an
  388. // anonymous class (as far as I know)...
  389. PrefixForUriEnumerator(NamespaceSupport2 nsup,String uri, Enumeration allPrefixes)
  390. {
  391. this.nsup=nsup;
  392. this.uri=uri;
  393. this.allPrefixes=allPrefixes;
  394. }
  395. public boolean hasMoreElements()
  396. {
  397. if(lookahead!=null)
  398. return true;
  399. while(allPrefixes.hasMoreElements())
  400. {
  401. String prefix=(String)allPrefixes.nextElement();
  402. if(uri.equals(nsup.getURI(prefix)))
  403. {
  404. lookahead=prefix;
  405. return true;
  406. }
  407. }
  408. return false;
  409. }
  410. public Object nextElement()
  411. {
  412. if(hasMoreElements())
  413. {
  414. String tmp=lookahead;
  415. lookahead=null;
  416. return tmp;
  417. }
  418. else
  419. throw new java.util.NoSuchElementException();
  420. }
  421. }
  422. /**
  423. * Internal class for a single Namespace context.
  424. *
  425. * <p>This module caches and reuses Namespace contexts, so the number allocated
  426. * will be equal to the element depth of the document, not to the total
  427. * number of elements (i.e. 5-10 rather than tens of thousands).</p>
  428. */
  429. final class Context2 {
  430. ////////////////////////////////////////////////////////////////
  431. // Manefest Constants
  432. ////////////////////////////////////////////////////////////////
  433. /**
  434. * An empty enumeration.
  435. */
  436. private final static Enumeration EMPTY_ENUMERATION =
  437. new Vector().elements();
  438. ////////////////////////////////////////////////////////////////
  439. // Protected state.
  440. ////////////////////////////////////////////////////////////////
  441. Hashtable prefixTable;
  442. Hashtable uriTable;
  443. Hashtable elementNameTable;
  444. Hashtable attributeNameTable;
  445. String defaultNS = null;
  446. ////////////////////////////////////////////////////////////////
  447. // Internal state.
  448. ////////////////////////////////////////////////////////////////
  449. private Vector declarations = null;
  450. private boolean tablesDirty = false;
  451. private Context2 parent = null;
  452. private Context2 child = null;
  453. /**
  454. * Create a new Namespace context.
  455. */
  456. Context2 (Context2 parent)
  457. {
  458. if(parent==null)
  459. {
  460. prefixTable = new Hashtable();
  461. uriTable = new Hashtable();
  462. elementNameTable=null;
  463. attributeNameTable=null;
  464. }
  465. else
  466. setParent(parent);
  467. }
  468. /**
  469. * @returns The child Namespace context object, or null if this
  470. * is the last currently on the chain.
  471. */
  472. Context2 getChild()
  473. {
  474. return child;
  475. }
  476. /**
  477. * @returns The parent Namespace context object, or null if this
  478. * is the root.
  479. */
  480. Context2 getParent()
  481. {
  482. return parent;
  483. }
  484. /**
  485. * (Re)set the parent of this Namespace context.
  486. * This is separate from the c'tor because it's re-applied
  487. * when a Context2 is reused by push-after-pop.
  488. *
  489. * @param context The parent Namespace context object.
  490. */
  491. void setParent (Context2 parent)
  492. {
  493. this.parent = parent;
  494. parent.child = this; // JJK: Doubly-linked
  495. declarations = null;
  496. prefixTable = parent.prefixTable;
  497. uriTable = parent.uriTable;
  498. elementNameTable = parent.elementNameTable;
  499. attributeNameTable = parent.attributeNameTable;
  500. defaultNS = parent.defaultNS;
  501. tablesDirty = false;
  502. }
  503. /**
  504. * Declare a Namespace prefix for this context.
  505. *
  506. * @param prefix The prefix to declare.
  507. * @param uri The associated Namespace URI.
  508. * @see org.xml.sax.helpers.NamespaceSupport2#declarePrefix
  509. */
  510. void declarePrefix (String prefix, String uri)
  511. {
  512. // Lazy processing...
  513. if (!tablesDirty) {
  514. copyTables();
  515. }
  516. if (declarations == null) {
  517. declarations = new Vector();
  518. }
  519. prefix = prefix.intern();
  520. uri = uri.intern();
  521. if ("".equals(prefix)) {
  522. if ("".equals(uri)) {
  523. defaultNS = null;
  524. } else {
  525. defaultNS = uri;
  526. }
  527. } else {
  528. prefixTable.put(prefix, uri);
  529. uriTable.put(uri, prefix); // may wipe out another prefix
  530. }
  531. declarations.addElement(prefix);
  532. }
  533. /**
  534. * Process a raw XML 1.0 name in this context.
  535. *
  536. * @param qName The raw XML 1.0 name.
  537. * @param isAttribute true if this is an attribute name.
  538. * @return An array of three strings containing the
  539. * URI part (or empty string), the local part,
  540. * and the raw name, all internalized, or null
  541. * if there is an undeclared prefix.
  542. * @see org.xml.sax.helpers.NamespaceSupport2#processName
  543. */
  544. String [] processName (String qName, boolean isAttribute)
  545. {
  546. String name[];
  547. Hashtable table;
  548. // Select the appropriate table.
  549. if (isAttribute) {
  550. if(elementNameTable==null)
  551. elementNameTable=new Hashtable();
  552. table = elementNameTable;
  553. } else {
  554. if(attributeNameTable==null)
  555. attributeNameTable=new Hashtable();
  556. table = attributeNameTable;
  557. }
  558. // Start by looking in the cache, and
  559. // return immediately if the name
  560. // is already known in this content
  561. name = (String[])table.get(qName);
  562. if (name != null) {
  563. return name;
  564. }
  565. // We haven't seen this name in this
  566. // context before.
  567. name = new String[3];
  568. int index = qName.indexOf(':');
  569. // No prefix.
  570. if (index == -1) {
  571. if (isAttribute || defaultNS == null) {
  572. name[0] = "";
  573. } else {
  574. name[0] = defaultNS;
  575. }
  576. name[1] = qName.intern();
  577. name[2] = name[1];
  578. }
  579. // Prefix
  580. else {
  581. String prefix = qName.substring(0, index);
  582. String local = qName.substring(index+1);
  583. String uri;
  584. if ("".equals(prefix)) {
  585. uri = defaultNS;
  586. } else {
  587. uri = (String)prefixTable.get(prefix);
  588. }
  589. if (uri == null) {
  590. return null;
  591. }
  592. name[0] = uri;
  593. name[1] = local.intern();
  594. name[2] = qName.intern();
  595. }
  596. // Save in the cache for future use.
  597. table.put(name[2], name);
  598. tablesDirty = true;
  599. return name;
  600. }
  601. /**
  602. * Look up the URI associated with a prefix in this context.
  603. *
  604. * @param prefix The prefix to look up.
  605. * @return The associated Namespace URI, or null if none is
  606. * declared.
  607. * @see org.xml.sax.helpers.NamespaceSupport2#getURI
  608. */
  609. String getURI (String prefix)
  610. {
  611. if ("".equals(prefix)) {
  612. return defaultNS;
  613. } else if (prefixTable == null) {
  614. return null;
  615. } else {
  616. return (String)prefixTable.get(prefix);
  617. }
  618. }
  619. /**
  620. * Look up one of the prefixes associated with a URI in this context.
  621. *
  622. * <p>Since many prefixes may be mapped to the same URI,
  623. * the return value may be unreliable.</p>
  624. *
  625. * @param uri The URI to look up.
  626. * @return The associated prefix, or null if none is declared.
  627. * @see org.xml.sax.helpers.NamespaceSupport2#getPrefix
  628. */
  629. String getPrefix (String uri)
  630. {
  631. if (uriTable == null) {
  632. return null;
  633. } else {
  634. return (String)uriTable.get(uri);
  635. }
  636. }
  637. /**
  638. * Return an enumeration of prefixes declared in this context.
  639. *
  640. * @return An enumeration of prefixes (possibly empty).
  641. * @see org.xml.sax.helpers.NamespaceSupport2#getDeclaredPrefixes
  642. */
  643. Enumeration getDeclaredPrefixes ()
  644. {
  645. if (declarations == null) {
  646. return EMPTY_ENUMERATION;
  647. } else {
  648. return declarations.elements();
  649. }
  650. }
  651. /**
  652. * Return an enumeration of all prefixes currently in force.
  653. *
  654. * <p>The default prefix, if in force, is <em>not</em>
  655. * returned, and will have to be checked for separately.</p>
  656. *
  657. * @return An enumeration of prefixes (never empty).
  658. * @see org.xml.sax.helpers.NamespaceSupport2#getPrefixes
  659. */
  660. Enumeration getPrefixes ()
  661. {
  662. if (prefixTable == null) {
  663. return EMPTY_ENUMERATION;
  664. } else {
  665. return prefixTable.keys();
  666. }
  667. }
  668. ////////////////////////////////////////////////////////////////
  669. // Internal methods.
  670. ////////////////////////////////////////////////////////////////
  671. /**
  672. * Copy on write for the internal tables in this context.
  673. *
  674. * <p>This class is optimized for the normal case where most
  675. * elements do not contain Namespace declarations. In that case,
  676. * the Context2 will share data structures with its parent.
  677. * New tables are obtained only when new declarations are issued,
  678. * so they can be popped off the stack.</p>
  679. *
  680. * <p> JJK: **** Alternative: each Context2 might declare
  681. * _only_ its local bindings, and delegate upward if not found.</p>
  682. */
  683. private void copyTables ()
  684. {
  685. // Start by copying our parent's bindings
  686. prefixTable = (Hashtable)prefixTable.clone();
  687. uriTable = (Hashtable)uriTable.clone();
  688. // Replace the caches with empty ones, rather than
  689. // trying to determine which bindings should be flushed.
  690. // As far as I can tell, these caches are never actually
  691. // used in Xalan... More efficient to remove the whole
  692. // cache system? ****
  693. if(elementNameTable!=null)
  694. elementNameTable=new Hashtable();
  695. if(attributeNameTable!=null)
  696. attributeNameTable=new Hashtable();
  697. tablesDirty = true;
  698. }
  699. }
  700. // end of NamespaceSupport2.java