1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 2000-2002 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 "Xerces" 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, International
  53. * Business Machines, Inc., http://www.apache.org. For more
  54. * information on the Apache Software Foundation, please see
  55. * <http://www.apache.org/>.
  56. */
  57. package com.sun.org.apache.xerces.internal.impl;
  58. import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
  59. import com.sun.org.apache.xerces.internal.util.SymbolTable;
  60. import com.sun.org.apache.xerces.internal.util.XMLSymbols;
  61. import com.sun.org.apache.xerces.internal.xni.Augmentations;
  62. import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
  63. import com.sun.org.apache.xerces.internal.xni.QName;
  64. import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
  65. import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler;
  66. import com.sun.org.apache.xerces.internal.xni.XMLLocator;
  67. import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
  68. import com.sun.org.apache.xerces.internal.xni.XMLString;
  69. import com.sun.org.apache.xerces.internal.xni.XNIException;
  70. import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent;
  71. import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
  72. import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
  73. import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentFilter;
  74. import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource;
  75. /**
  76. * This class performs namespace binding on the startElement and endElement
  77. * method calls and passes all other methods through to the registered
  78. * document handler. This class can be configured to only pass the
  79. * start and end prefix mappings (start/endPrefixMapping).
  80. * <p>
  81. * This component requires the following features and properties from the
  82. * component manager that uses it:
  83. * <ul>
  84. * <li>http://xml.org/sax/features/namespaces</li>
  85. * <li>http://apache.org/xml/properties/internal/symbol-table</li>
  86. * <li>http://apache.org/xml/properties/internal/error-reporter</li>
  87. * </ul>
  88. *
  89. * @author Andy Clark, IBM
  90. *
  91. * @version $Id: XMLNamespaceBinder.java,v 1.33 2004/02/24 23:03:46 mrglavas Exp $
  92. */
  93. public class XMLNamespaceBinder
  94. implements XMLComponent, XMLDocumentFilter {
  95. //
  96. // Constants
  97. //
  98. // feature identifiers
  99. /** Feature identifier: namespaces. */
  100. protected static final String NAMESPACES =
  101. Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE;
  102. // property identifiers
  103. /** Property identifier: symbol table. */
  104. protected static final String SYMBOL_TABLE =
  105. Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
  106. /** Property identifier: error reporter. */
  107. protected static final String ERROR_REPORTER =
  108. Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
  109. // recognized features and properties
  110. /** Recognized features. */
  111. private static final String[] RECOGNIZED_FEATURES = {
  112. NAMESPACES,
  113. };
  114. /** Feature defaults. */
  115. private static final Boolean[] FEATURE_DEFAULTS = {
  116. null,
  117. };
  118. /** Recognized properties. */
  119. private static final String[] RECOGNIZED_PROPERTIES = {
  120. SYMBOL_TABLE,
  121. ERROR_REPORTER,
  122. };
  123. /** Property defaults. */
  124. private static final Object[] PROPERTY_DEFAULTS = {
  125. null,
  126. null,
  127. };
  128. //
  129. // Data
  130. //
  131. // features
  132. /** Namespaces. */
  133. protected boolean fNamespaces;
  134. // properties
  135. /** Symbol table. */
  136. protected SymbolTable fSymbolTable;
  137. /** Error reporter. */
  138. protected XMLErrorReporter fErrorReporter;
  139. // handlers
  140. /** Document handler. */
  141. protected XMLDocumentHandler fDocumentHandler;
  142. protected XMLDocumentSource fDocumentSource;
  143. // settings
  144. /** Only pass start and end prefix mapping events. */
  145. protected boolean fOnlyPassPrefixMappingEvents;
  146. // shared context
  147. /** Namespace context. */
  148. private NamespaceContext fNamespaceContext;
  149. // temp vars
  150. /** Attribute QName. */
  151. private QName fAttributeQName = new QName();
  152. //
  153. // Constructors
  154. //
  155. /** Default constructor. */
  156. public XMLNamespaceBinder() {
  157. } // <init>()
  158. //
  159. // Public methods
  160. //
  161. // settings
  162. /**
  163. * Sets whether the namespace binder only passes the prefix mapping
  164. * events to the registered document handler or passes all document
  165. * events.
  166. *
  167. * @param onlyPassPrefixMappingEvents True to pass only the prefix
  168. * mapping events; false to pass
  169. * all events.
  170. */
  171. public void setOnlyPassPrefixMappingEvents(boolean onlyPassPrefixMappingEvents) {
  172. fOnlyPassPrefixMappingEvents = onlyPassPrefixMappingEvents;
  173. } // setOnlyPassPrefixMappingEvents(boolean)
  174. /**
  175. * Returns true if the namespace binder only passes the prefix mapping
  176. * events to the registered document handler; false if the namespace
  177. * binder passes all document events.
  178. */
  179. public boolean getOnlyPassPrefixMappingEvents() {
  180. return fOnlyPassPrefixMappingEvents;
  181. } // getOnlyPassPrefixMappingEvents():boolean
  182. //
  183. // XMLComponent methods
  184. //
  185. /**
  186. * Resets the component. The component can query the component manager
  187. * about any features and properties that affect the operation of the
  188. * component.
  189. *
  190. * @param componentManager The component manager.
  191. *
  192. * @throws SAXException Thrown by component on initialization error.
  193. * For example, if a feature or property is
  194. * required for the operation of the component, the
  195. * component manager may throw a
  196. * SAXNotRecognizedException or a
  197. * SAXNotSupportedException.
  198. */
  199. public void reset(XMLComponentManager componentManager)
  200. throws XNIException {
  201. // features
  202. try {
  203. fNamespaces = componentManager.getFeature(NAMESPACES);
  204. }
  205. catch (XMLConfigurationException e) {
  206. fNamespaces = true;
  207. }
  208. // Xerces properties
  209. fSymbolTable = (SymbolTable)componentManager.getProperty(SYMBOL_TABLE);
  210. fErrorReporter = (XMLErrorReporter)componentManager.getProperty(ERROR_REPORTER);
  211. } // reset(XMLComponentManager)
  212. /**
  213. * Returns a list of feature identifiers that are recognized by
  214. * this component. This method may return null if no features
  215. * are recognized by this component.
  216. */
  217. public String[] getRecognizedFeatures() {
  218. return (String[])(RECOGNIZED_FEATURES.clone());
  219. } // getRecognizedFeatures():String[]
  220. /**
  221. * Sets the state of a feature. This method is called by the component
  222. * manager any time after reset when a feature changes state.
  223. * <p>
  224. * <strong>Note:</strong> Components should silently ignore features
  225. * that do not affect the operation of the component.
  226. *
  227. * @param featureId The feature identifier.
  228. * @param state The state of the feature.
  229. *
  230. * @throws SAXNotRecognizedException The component should not throw
  231. * this exception.
  232. * @throws SAXNotSupportedException The component should not throw
  233. * this exception.
  234. */
  235. public void setFeature(String featureId, boolean state)
  236. throws XMLConfigurationException {
  237. } // setFeature(String,boolean)
  238. /**
  239. * Returns a list of property identifiers that are recognized by
  240. * this component. This method may return null if no properties
  241. * are recognized by this component.
  242. */
  243. public String[] getRecognizedProperties() {
  244. return (String[])(RECOGNIZED_PROPERTIES.clone());
  245. } // getRecognizedProperties():String[]
  246. /**
  247. * Sets the value of a property during parsing.
  248. *
  249. * @param propertyId
  250. * @param value
  251. */
  252. public void setProperty(String propertyId, Object value)
  253. throws XMLConfigurationException {
  254. // Xerces properties
  255. if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) {
  256. final int suffixLength = propertyId.length() - Constants.XERCES_PROPERTY_PREFIX.length();
  257. if (suffixLength == Constants.SYMBOL_TABLE_PROPERTY.length() &&
  258. propertyId.endsWith(Constants.SYMBOL_TABLE_PROPERTY)) {
  259. fSymbolTable = (SymbolTable)value;
  260. }
  261. else if (suffixLength == Constants.ERROR_REPORTER_PROPERTY.length() &&
  262. propertyId.endsWith(Constants.ERROR_REPORTER_PROPERTY)) {
  263. fErrorReporter = (XMLErrorReporter)value;
  264. }
  265. return;
  266. }
  267. } // setProperty(String,Object)
  268. /**
  269. * Returns the default state for a feature, or null if this
  270. * component does not want to report a default value for this
  271. * feature.
  272. *
  273. * @param featureId The feature identifier.
  274. *
  275. * @since Xerces 2.2.0
  276. */
  277. public Boolean getFeatureDefault(String featureId) {
  278. for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) {
  279. if (RECOGNIZED_FEATURES[i].equals(featureId)) {
  280. return FEATURE_DEFAULTS[i];
  281. }
  282. }
  283. return null;
  284. } // getFeatureDefault(String):Boolean
  285. /**
  286. * Returns the default state for a property, or null if this
  287. * component does not want to report a default value for this
  288. * property.
  289. *
  290. * @param propertyId The property identifier.
  291. *
  292. * @since Xerces 2.2.0
  293. */
  294. public Object getPropertyDefault(String propertyId) {
  295. for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) {
  296. if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) {
  297. return PROPERTY_DEFAULTS[i];
  298. }
  299. }
  300. return null;
  301. } // getPropertyDefault(String):Object
  302. //
  303. // XMLDocumentSource methods
  304. //
  305. /** Sets the document handler to receive information about the document. */
  306. public void setDocumentHandler(XMLDocumentHandler documentHandler) {
  307. fDocumentHandler = documentHandler;
  308. } // setDocumentHandler(XMLDocumentHandler)
  309. /** Returns the document handler */
  310. public XMLDocumentHandler getDocumentHandler() {
  311. return fDocumentHandler;
  312. } // setDocumentHandler(XMLDocumentHandler)
  313. //
  314. // XMLDocumentHandler methods
  315. //
  316. /** Sets the document source */
  317. public void setDocumentSource(XMLDocumentSource source){
  318. fDocumentSource = source;
  319. } // setDocumentSource
  320. /** Returns the document source */
  321. public XMLDocumentSource getDocumentSource (){
  322. return fDocumentSource;
  323. } // getDocumentSource
  324. /**
  325. * This method notifies the start of a general entity.
  326. * <p>
  327. * <strong>Note:</strong> This method is not called for entity references
  328. * appearing as part of attribute values.
  329. *
  330. * @param name The name of the general entity.
  331. * @param identifier The resource identifier.
  332. * @param encoding The auto-detected IANA encoding name of the entity
  333. * stream. This value will be null in those situations
  334. * where the entity encoding is not auto-detected (e.g.
  335. * internal entities or a document entity that is
  336. * parsed from a java.io.Reader).
  337. * @param augs Additional information that may include infoset augmentations
  338. *
  339. * @exception XNIException Thrown by handler to signal an error.
  340. */
  341. public void startGeneralEntity(String name,
  342. XMLResourceIdentifier identifier,
  343. String encoding, Augmentations augs)
  344. throws XNIException {
  345. if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) {
  346. fDocumentHandler.startGeneralEntity(name, identifier, encoding, augs);
  347. }
  348. } // startEntity(String,String,String,String,String)
  349. /**
  350. * Notifies of the presence of a TextDecl line in an entity. If present,
  351. * this method will be called immediately following the startEntity call.
  352. * <p>
  353. * <strong>Note:</strong> This method will never be called for the
  354. * document entity; it is only called for external general entities
  355. * referenced in document content.
  356. * <p>
  357. * <strong>Note:</strong> This method is not called for entity references
  358. * appearing as part of attribute values.
  359. *
  360. * @param version The XML version, or null if not specified.
  361. * @param encoding The IANA encoding name of the entity.
  362. * @param augs Additional information that may include infoset augmentations
  363. *
  364. * @throws XNIException Thrown by handler to signal an error.
  365. */
  366. public void textDecl(String version, String encoding, Augmentations augs)
  367. throws XNIException {
  368. if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) {
  369. fDocumentHandler.textDecl(version, encoding, augs);
  370. }
  371. } // textDecl(String,String)
  372. /**
  373. * The start of the document.
  374. *
  375. * @param locator The system identifier of the entity if the entity
  376. * is external, null otherwise.
  377. * @param encoding The auto-detected IANA encoding name of the entity
  378. * stream. This value will be null in those situations
  379. * where the entity encoding is not auto-detected (e.g.
  380. * internal entities or a document entity that is
  381. * parsed from a java.io.Reader).
  382. * @param namespaceContext
  383. * The namespace context in effect at the
  384. * start of this document.
  385. * This object represents the current context.
  386. * Implementors of this class are responsible
  387. * for copying the namespace bindings from the
  388. * the current context (and its parent contexts)
  389. * if that information is important.
  390. * @param augs Additional information that may include infoset augmentations
  391. *
  392. * @throws XNIException Thrown by handler to signal an error.
  393. */
  394. public void startDocument(XMLLocator locator, String encoding,
  395. NamespaceContext namespaceContext, Augmentations augs)
  396. throws XNIException {
  397. fNamespaceContext = namespaceContext;
  398. if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) {
  399. fDocumentHandler.startDocument(locator, encoding, namespaceContext, augs);
  400. }
  401. } // startDocument(XMLLocator,String)
  402. /**
  403. * Notifies of the presence of an XMLDecl line in the document. If
  404. * present, this method will be called immediately following the
  405. * startDocument call.
  406. *
  407. * @param version The XML version.
  408. * @param encoding The IANA encoding name of the document, or null if
  409. * not specified.
  410. * @param standalone The standalone value, or null if not specified.
  411. * @param augs Additional information that may include infoset augmentations
  412. *
  413. * @throws XNIException Thrown by handler to signal an error.
  414. */
  415. public void xmlDecl(String version, String encoding, String standalone, Augmentations augs)
  416. throws XNIException {
  417. if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) {
  418. fDocumentHandler.xmlDecl(version, encoding, standalone, augs);
  419. }
  420. } // xmlDecl(String,String,String)
  421. /**
  422. * Notifies of the presence of the DOCTYPE line in the document.
  423. *
  424. * @param rootElement The name of the root element.
  425. * @param publicId The public identifier if an external DTD or null
  426. * if the external DTD is specified using SYSTEM.
  427. * @param systemId The system identifier if an external DTD, null
  428. * otherwise.
  429. * @param augs Additional information that may include infoset augmentations
  430. *
  431. * @throws XNIException Thrown by handler to signal an error.
  432. */
  433. public void doctypeDecl(String rootElement,
  434. String publicId, String systemId, Augmentations augs)
  435. throws XNIException {
  436. if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) {
  437. fDocumentHandler.doctypeDecl(rootElement, publicId, systemId, augs);
  438. }
  439. } // doctypeDecl(String,String,String)
  440. /**
  441. * A comment.
  442. *
  443. * @param text The text in the comment.
  444. * @param augs Additional information that may include infoset augmentations
  445. *
  446. * @throws XNIException Thrown by application to signal an error.
  447. */
  448. public void comment(XMLString text, Augmentations augs) throws XNIException {
  449. if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) {
  450. fDocumentHandler.comment(text, augs);
  451. }
  452. } // comment(XMLString)
  453. /**
  454. * A processing instruction. Processing instructions consist of a
  455. * target name and, optionally, text data. The data is only meaningful
  456. * to the application.
  457. * <p>
  458. * Typically, a processing instruction's data will contain a series
  459. * of pseudo-attributes. These pseudo-attributes follow the form of
  460. * element attributes but are <strong>not</strong> parsed or presented
  461. * to the application as anything other than text. The application is
  462. * responsible for parsing the data.
  463. *
  464. * @param target The target.
  465. * @param data The data or null if none specified.
  466. * @param augs Additional information that may include infoset augmentations
  467. *
  468. * @throws XNIException Thrown by handler to signal an error.
  469. */
  470. public void processingInstruction(String target, XMLString data, Augmentations augs)
  471. throws XNIException {
  472. if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) {
  473. fDocumentHandler.processingInstruction(target, data, augs);
  474. }
  475. } // processingInstruction(String,XMLString)
  476. /**
  477. * Binds the namespaces. This method will handle calling the
  478. * document handler to start the prefix mappings.
  479. * <p>
  480. * <strong>Note:</strong> This method makes use of the
  481. * fAttributeQName variable. Any contents of the variable will
  482. * be destroyed. Caller should copy the values out of this
  483. * temporary variable before calling this method.
  484. *
  485. * @param element The name of the element.
  486. * @param attributes The element attributes.
  487. * @param augs Additional information that may include infoset augmentations
  488. *
  489. * @throws XNIException Thrown by handler to signal an error.
  490. */
  491. public void startElement(QName element, XMLAttributes attributes, Augmentations augs)
  492. throws XNIException {
  493. if (fNamespaces) {
  494. handleStartElement(element, attributes, augs, false);
  495. }
  496. else if (fDocumentHandler != null) {
  497. fDocumentHandler.startElement(element, attributes, augs);
  498. }
  499. } // startElement(QName,XMLAttributes)
  500. /**
  501. * An empty element.
  502. *
  503. * @param element The name of the element.
  504. * @param attributes The element attributes.
  505. * @param augs Additional information that may include infoset augmentations
  506. *
  507. * @throws XNIException Thrown by handler to signal an error.
  508. */
  509. public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs)
  510. throws XNIException {
  511. if (fNamespaces) {
  512. handleStartElement(element, attributes, augs, true);
  513. handleEndElement(element, augs, true);
  514. }
  515. else if (fDocumentHandler != null) {
  516. fDocumentHandler.emptyElement(element, attributes, augs);
  517. }
  518. } // emptyElement(QName,XMLAttributes)
  519. /**
  520. * Character content.
  521. *
  522. * @param text The content.
  523. * @param augs Additional information that may include infoset augmentations
  524. *
  525. * @throws XNIException Thrown by handler to signal an error.
  526. */
  527. public void characters(XMLString text, Augmentations augs) throws XNIException {
  528. if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) {
  529. fDocumentHandler.characters(text, augs);
  530. }
  531. } // characters(XMLString)
  532. /**
  533. * Ignorable whitespace. For this method to be called, the document
  534. * source must have some way of determining that the text containing
  535. * only whitespace characters should be considered ignorable. For
  536. * example, the validator can determine if a length of whitespace
  537. * characters in the document are ignorable based on the element
  538. * content model.
  539. *
  540. * @param text The ignorable whitespace.
  541. * @param augs Additional information that may include infoset augmentations
  542. *
  543. * @throws XNIException Thrown by handler to signal an error.
  544. */
  545. public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException {
  546. if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) {
  547. fDocumentHandler.ignorableWhitespace(text, augs);
  548. }
  549. } // ignorableWhitespace(XMLString)
  550. /**
  551. * The end of an element.
  552. *
  553. * @param element The name of the element.
  554. * @param augs Additional information that may include infoset augmentations
  555. *
  556. * @throws XNIException Thrown by handler to signal an error.
  557. */
  558. public void endElement(QName element, Augmentations augs) throws XNIException {
  559. if (fNamespaces) {
  560. handleEndElement(element, augs, false);
  561. }
  562. else if (fDocumentHandler != null) {
  563. fDocumentHandler.endElement(element, augs);
  564. }
  565. } // endElement(QName)
  566. /**
  567. * The start of a CDATA section.
  568. * @param augs Additional information that may include infoset augmentations
  569. *
  570. * @throws XNIException Thrown by handler to signal an error.
  571. */
  572. public void startCDATA(Augmentations augs) throws XNIException {
  573. if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) {
  574. fDocumentHandler.startCDATA(augs);
  575. }
  576. } // startCDATA()
  577. /**
  578. * The end of a CDATA section.
  579. * @param augs Additional information that may include infoset augmentations
  580. *
  581. * @throws XNIException Thrown by handler to signal an error.
  582. */
  583. public void endCDATA(Augmentations augs) throws XNIException {
  584. if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) {
  585. fDocumentHandler.endCDATA(augs);
  586. }
  587. } // endCDATA()
  588. /**
  589. * The end of the document.
  590. * @param augs Additional information that may include infoset augmentations
  591. *
  592. * @throws XNIException Thrown by handler to signal an error.
  593. */
  594. public void endDocument(Augmentations augs) throws XNIException {
  595. if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) {
  596. fDocumentHandler.endDocument(augs);
  597. }
  598. } // endDocument()
  599. /**
  600. * This method notifies the end of a general entity.
  601. * <p>
  602. * <strong>Note:</strong> This method is not called for entity references
  603. * appearing as part of attribute values.
  604. *
  605. * @param name The name of the entity.
  606. * @param augs Additional information that may include infoset augmentations
  607. *
  608. * @exception XNIException
  609. * Thrown by handler to signal an error.
  610. */
  611. public void endGeneralEntity(String name, Augmentations augs) throws XNIException {
  612. if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) {
  613. fDocumentHandler.endGeneralEntity(name, augs);
  614. }
  615. } // endEntity(String)
  616. //
  617. // Protected methods
  618. //
  619. /** Handles start element. */
  620. protected void handleStartElement(QName element, XMLAttributes attributes,
  621. Augmentations augs,
  622. boolean isEmpty) throws XNIException {
  623. // add new namespace context
  624. fNamespaceContext.pushContext();
  625. if (element.prefix == XMLSymbols.PREFIX_XMLNS) {
  626. fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
  627. "ElementXMLNSPrefix",
  628. new Object[]{element.rawname},
  629. XMLErrorReporter.SEVERITY_FATAL_ERROR);
  630. }
  631. // search for new namespace bindings
  632. int length = attributes.getLength();
  633. for (int i = 0; i < length; i++) {
  634. String localpart = attributes.getLocalName(i);
  635. String prefix = attributes.getPrefix(i);
  636. // when it's of form xmlns="..." or xmlns:prefix="...",
  637. // it's a namespace declaration. but prefix:xmlns="..." isn't.
  638. if (prefix == XMLSymbols.PREFIX_XMLNS ||
  639. prefix == XMLSymbols.EMPTY_STRING && localpart == XMLSymbols.PREFIX_XMLNS) {
  640. // get the internalized value of this attribute
  641. String uri = fSymbolTable.addSymbol(attributes.getValue(i));
  642. // 1. "xmlns" can't be bound to any namespace
  643. if (prefix == XMLSymbols.PREFIX_XMLNS && localpart == XMLSymbols.PREFIX_XMLNS) {
  644. fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
  645. "CantBindXMLNS",
  646. new Object[]{attributes.getQName(i)},
  647. XMLErrorReporter.SEVERITY_FATAL_ERROR);
  648. }
  649. // 2. the namespace for "xmlns" can't be bound to any prefix
  650. if (uri == NamespaceContext.XMLNS_URI) {
  651. fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
  652. "CantBindXMLNS",
  653. new Object[]{attributes.getQName(i)},
  654. XMLErrorReporter.SEVERITY_FATAL_ERROR);
  655. }
  656. // 3. "xml" can't be bound to any other namespace than it's own
  657. if (localpart == XMLSymbols.PREFIX_XML) {
  658. if (uri != NamespaceContext.XML_URI) {
  659. fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
  660. "CantBindXML",
  661. new Object[]{attributes.getQName(i)},
  662. XMLErrorReporter.SEVERITY_FATAL_ERROR);
  663. }
  664. }
  665. // 4. the namespace for "xml" can't be bound to any other prefix
  666. else {
  667. if (uri ==NamespaceContext.XML_URI) {
  668. fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
  669. "CantBindXML",
  670. new Object[]{attributes.getQName(i)},
  671. XMLErrorReporter.SEVERITY_FATAL_ERROR);
  672. }
  673. }
  674. prefix = localpart != XMLSymbols.PREFIX_XMLNS ? localpart : XMLSymbols.EMPTY_STRING;
  675. // http://www.w3.org/TR/1999/REC-xml-names-19990114/#dt-prefix
  676. // We should only report an error if there is a prefix,
  677. // that is, the local part is not "xmlns". -SG
  678. // Since this is an error condition in XML 1.0,
  679. // and should be relatively uncommon in XML 1.1,
  680. // making this test into a method call to reuse code
  681. // should be acceptable. - NG
  682. if(prefixBoundToNullURI(uri, localpart)) {
  683. fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
  684. "EmptyPrefixedAttName",
  685. new Object[]{attributes.getQName(i)},
  686. XMLErrorReporter.SEVERITY_FATAL_ERROR);
  687. continue;
  688. }
  689. // declare prefix in context
  690. fNamespaceContext.declarePrefix(prefix, uri.length() != 0 ? uri : null);
  691. }
  692. }
  693. // bind the element
  694. String prefix = element.prefix != null
  695. ? element.prefix : XMLSymbols.EMPTY_STRING;
  696. element.uri = fNamespaceContext.getURI(prefix);
  697. if (element.prefix == null && element.uri != null) {
  698. element.prefix = XMLSymbols.EMPTY_STRING;
  699. }
  700. if (element.prefix != null && element.uri == null) {
  701. fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
  702. "ElementPrefixUnbound",
  703. new Object[]{element.prefix, element.rawname},
  704. XMLErrorReporter.SEVERITY_FATAL_ERROR);
  705. }
  706. // bind the attributes
  707. for (int i = 0; i < length; i++) {
  708. attributes.getName(i, fAttributeQName);
  709. String aprefix = fAttributeQName.prefix != null
  710. ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING;
  711. String arawname = fAttributeQName.rawname;
  712. if (arawname == XMLSymbols.PREFIX_XMLNS) {
  713. fAttributeQName.uri = fNamespaceContext.getURI(XMLSymbols.PREFIX_XMLNS);
  714. attributes.setName(i, fAttributeQName);
  715. }
  716. else if (aprefix != XMLSymbols.EMPTY_STRING) {
  717. fAttributeQName.uri = fNamespaceContext.getURI(aprefix);
  718. if (fAttributeQName.uri == null) {
  719. fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
  720. "AttributePrefixUnbound",
  721. new Object[]{element.rawname,arawname,aprefix},
  722. XMLErrorReporter.SEVERITY_FATAL_ERROR);
  723. }
  724. attributes.setName(i, fAttributeQName);
  725. }
  726. }
  727. // verify that duplicate attributes don't exist
  728. // Example: <foo xmlns:a='NS' xmlns:b='NS' a:attr='v1' b:attr='v2'/>
  729. int attrCount = attributes.getLength();
  730. for (int i = 0; i < attrCount - 1; i++) {
  731. String auri = attributes.getURI(i);
  732. if (auri == null || auri == NamespaceContext.XMLNS_URI) {
  733. continue;
  734. }
  735. String alocalpart = attributes.getLocalName(i);
  736. for (int j = i + 1; j < attrCount; j++) {
  737. String blocalpart = attributes.getLocalName(j);
  738. String buri = attributes.getURI(j);
  739. if (alocalpart == blocalpart && auri == buri) {
  740. fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
  741. "AttributeNSNotUnique",
  742. new Object[]{element.rawname,alocalpart, auri},
  743. XMLErrorReporter.SEVERITY_FATAL_ERROR);
  744. }
  745. }
  746. }
  747. // call handler
  748. if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) {
  749. if (isEmpty) {
  750. fDocumentHandler.emptyElement(element, attributes, augs);
  751. }
  752. else {
  753. fDocumentHandler.startElement(element, attributes, augs);
  754. }
  755. }
  756. } // handleStartElement(QName,XMLAttributes,boolean)
  757. /** Handles end element. */
  758. protected void handleEndElement(QName element, Augmentations augs, boolean isEmpty)
  759. throws XNIException {
  760. // bind element
  761. String eprefix = element.prefix != null ? element.prefix : XMLSymbols.EMPTY_STRING;
  762. element.uri = fNamespaceContext.getURI(eprefix);
  763. if (element.uri != null) {
  764. element.prefix = eprefix;
  765. }
  766. // call handlers
  767. if (fDocumentHandler != null && !fOnlyPassPrefixMappingEvents) {
  768. if (!isEmpty) {
  769. fDocumentHandler.endElement(element, augs);
  770. }
  771. }
  772. // pop context
  773. fNamespaceContext.popContext();
  774. } // handleEndElement(QName,boolean)
  775. // returns true iff the given prefix is bound to "" *and*
  776. // this is disallowed by the version of XML namespaces in use.
  777. protected boolean prefixBoundToNullURI(String uri, String localpart) {
  778. return (uri == XMLSymbols.EMPTY_STRING && localpart != XMLSymbols.PREFIX_XMLNS);
  779. } // prefixBoundToNullURI(String, String): boolean
  780. } // class XMLNamespaceBinder