1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 1999-2002 The Apache Software Foundation.
  6. * All rights 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) 2002, 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 java.io.IOException;
  59. import com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidatorFilter;
  60. import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
  61. import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl;
  62. import com.sun.org.apache.xerces.internal.util.XMLSymbols;
  63. import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
  64. import com.sun.org.apache.xerces.internal.xni.QName;
  65. import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler;
  66. import com.sun.org.apache.xerces.internal.xni.XNIException;
  67. import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
  68. import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
  69. import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource;
  70. /**
  71. * The scanner acts as the source for the document
  72. * information which is communicated to the document handler.
  73. *
  74. * This class scans an XML document, checks if document has a DTD, and if
  75. * DTD is not found the scanner will remove the DTD Validator from the pipeline and perform
  76. * namespace binding.
  77. *
  78. * Note: This scanner should only be used when the namespace processing is on!
  79. *
  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 {true} -- if the value of this
  85. * feature is set to false this scanner must not be used.</li>
  86. * <li>http://xml.org/sax/features/validation</li>
  87. * <li>http://apache.org/xml/features/nonvalidating/load-external-dtd</li>
  88. * <li>http://apache.org/xml/features/scanner/notify-char-refs</li>
  89. * <li>http://apache.org/xml/features/scanner/notify-builtin-refs</li>
  90. * <li>http://apache.org/xml/properties/internal/symbol-table</li>
  91. * <li>http://apache.org/xml/properties/internal/error-reporter</li>
  92. * <li>http://apache.org/xml/properties/internal/entity-manager</li>
  93. * <li>http://apache.org/xml/properties/internal/dtd-scanner</li>
  94. * </ul>
  95. *
  96. * @author Elena Litani, IBM
  97. *
  98. * @version $Id: XMLNSDocumentScannerImpl.java,v 1.23 2004/04/30 15:36:38 mrglavas Exp $
  99. */
  100. public class XMLNSDocumentScannerImpl
  101. extends XMLDocumentScannerImpl {
  102. /** If is true, the dtd validator is no longer in the pipeline
  103. * and the scanner should bind namespaces */
  104. protected boolean fBindNamespaces;
  105. /** If validating parser, make sure we report an error in the
  106. * scanner if DTD grammar is missing.*/
  107. protected boolean fPerformValidation;
  108. // private data
  109. //
  110. /** DTD validator */
  111. private XMLDTDValidatorFilter fDTDValidator;
  112. /**
  113. * Saw spaces after element name or between attributes.
  114. *
  115. * This is reserved for the case where scanning of a start element spans
  116. * several methods, as is the case when scanning the start of a root element
  117. * where a DTD external subset may be read after scanning the element name.
  118. */
  119. private boolean fSawSpace;
  120. /**
  121. * The scanner is responsible for removing DTD validator
  122. * from the pipeline if it is not needed.
  123. *
  124. * @param previous The filter component before DTDValidator
  125. * @param dtdValidator
  126. * The DTDValidator
  127. * @param next The documentHandler after the DTDValidator
  128. */
  129. public void setDTDValidator(XMLDTDValidatorFilter dtd){
  130. fDTDValidator = dtd;
  131. }
  132. /**
  133. * Scans a start element. This method will handle the binding of
  134. * namespace information and notifying the handler of the start
  135. * of the element.
  136. * <p>
  137. * <pre>
  138. * [44] EmptyElemTag ::= '<' Name (S Attribute)* S? '/>'
  139. * [40] STag ::= '<' Name (S Attribute)* S? '>'
  140. * </pre>
  141. * <p>
  142. * <strong>Note:</strong> This method assumes that the leading
  143. * '<' character has been consumed.
  144. * <p>
  145. * <strong>Note:</strong> This method uses the fElementQName and
  146. * fAttributes variables. The contents of these variables will be
  147. * destroyed. The caller should copy important information out of
  148. * these variables before calling this method.
  149. *
  150. * @return True if element is empty. (i.e. It matches
  151. * production [44].
  152. */
  153. protected boolean scanStartElement()
  154. throws IOException, XNIException {
  155. if (DEBUG_CONTENT_SCANNING) System.out.println(">>> scanStartElementNS()");
  156. // Note: namespace processing is on by default
  157. fEntityScanner.scanQName(fElementQName);
  158. // REVISIT - [Q] Why do we need this temp variable? -- mrglavas
  159. String rawname = fElementQName.rawname;
  160. if (fBindNamespaces) {
  161. fNamespaceContext.pushContext();
  162. if (fScannerState == SCANNER_STATE_ROOT_ELEMENT) {
  163. if (fPerformValidation) {
  164. fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
  165. "MSG_GRAMMAR_NOT_FOUND",
  166. new Object[]{ rawname},
  167. XMLErrorReporter.SEVERITY_ERROR);
  168. if (fDoctypeName == null || !fDoctypeName.equals(rawname)) {
  169. fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN,
  170. "RootElementTypeMustMatchDoctypedecl",
  171. new Object[]{fDoctypeName, rawname},
  172. XMLErrorReporter.SEVERITY_ERROR);
  173. }
  174. }
  175. }
  176. }
  177. // push element stack
  178. fCurrentElement = fElementStack.pushElement(fElementQName);
  179. // attributes
  180. boolean empty = false;
  181. fAttributes.removeAllAttributes();
  182. do {
  183. // spaces
  184. boolean sawSpace = fEntityScanner.skipSpaces();
  185. // end tag?
  186. int c = fEntityScanner.peekChar();
  187. if (c == '>') {
  188. fEntityScanner.scanChar();
  189. break;
  190. }
  191. else if (c == '/') {
  192. fEntityScanner.scanChar();
  193. if (!fEntityScanner.skipChar('>')) {
  194. reportFatalError("ElementUnterminated",
  195. new Object[]{rawname});
  196. }
  197. empty = true;
  198. break;
  199. }
  200. else if (!isValidNameStartChar(c) || !sawSpace) {
  201. reportFatalError("ElementUnterminated", new Object[]{rawname});
  202. }
  203. // attributes
  204. scanAttribute(fAttributes);
  205. } while (true);
  206. if (fBindNamespaces) {
  207. // REVISIT: is it required? forbit xmlns prefix for element
  208. if (fElementQName.prefix == XMLSymbols.PREFIX_XMLNS) {
  209. fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
  210. "ElementXMLNSPrefix",
  211. new Object[]{fElementQName.rawname},
  212. XMLErrorReporter.SEVERITY_FATAL_ERROR);
  213. }
  214. // bind the element
  215. String prefix = fElementQName.prefix != null
  216. ? fElementQName.prefix : XMLSymbols.EMPTY_STRING;
  217. // assign uri to the element
  218. fElementQName.uri = fNamespaceContext.getURI(prefix);
  219. // make sure that object in the element stack is updated as well
  220. fCurrentElement.uri = fElementQName.uri;
  221. if (fElementQName.prefix == null && fElementQName.uri != null) {
  222. fElementQName.prefix = XMLSymbols.EMPTY_STRING;
  223. // making sure that the object in the element stack is updated too.
  224. fCurrentElement.prefix = XMLSymbols.EMPTY_STRING;
  225. }
  226. if (fElementQName.prefix != null && fElementQName.uri == null) {
  227. fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
  228. "ElementPrefixUnbound",
  229. new Object[]{fElementQName.prefix, fElementQName.rawname},
  230. XMLErrorReporter.SEVERITY_FATAL_ERROR);
  231. }
  232. // bind attributes (xmlns are already bound bellow)
  233. int length = fAttributes.getLength();
  234. // fLength = 0; //initialize structure
  235. for (int i = 0; i < length; i++) {
  236. fAttributes.getName(i, fAttributeQName);
  237. String aprefix = fAttributeQName.prefix != null
  238. ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING;
  239. String uri = fNamespaceContext.getURI(aprefix);
  240. // REVISIT: try removing the first "if" and see if it is faster.
  241. //
  242. if (fAttributeQName.uri != null && fAttributeQName.uri == uri) {
  243. // checkDuplicates(fAttributeQName, fAttributes);
  244. continue;
  245. }
  246. if (aprefix != XMLSymbols.EMPTY_STRING) {
  247. fAttributeQName.uri = uri;
  248. if (uri == null) {
  249. fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
  250. "AttributePrefixUnbound",
  251. new Object[]{fElementQName.rawname,fAttributeQName.rawname,aprefix},
  252. XMLErrorReporter.SEVERITY_FATAL_ERROR);
  253. }
  254. fAttributes.setURI(i, uri);
  255. // checkDuplicates(fAttributeQName, fAttributes);
  256. }
  257. }
  258. if (length > 1) {
  259. QName name = fAttributes.checkDuplicatesNS();
  260. if (name != null) {
  261. if (name.uri != null) {
  262. fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
  263. "AttributeNSNotUnique",
  264. new Object[]{fElementQName.rawname, name.localpart, name.uri},
  265. XMLErrorReporter.SEVERITY_FATAL_ERROR);
  266. }
  267. else {
  268. fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
  269. "AttributeNotUnique",
  270. new Object[]{fElementQName.rawname, name.rawname},
  271. XMLErrorReporter.SEVERITY_FATAL_ERROR);
  272. }
  273. }
  274. }
  275. }
  276. // call handler
  277. if (fDocumentHandler != null) {
  278. if (empty) {
  279. //decrease the markup depth..
  280. fMarkupDepth--;
  281. // check that this element was opened in the same entity
  282. if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) {
  283. reportFatalError("ElementEntityMismatch",
  284. new Object[]{fCurrentElement.rawname});
  285. }
  286. fDocumentHandler.emptyElement(fElementQName, fAttributes, null);
  287. if (fBindNamespaces) {
  288. fNamespaceContext.popContext();
  289. }
  290. //pop the element off the stack..
  291. fElementStack.popElement(fElementQName);
  292. } else {
  293. fDocumentHandler.startElement(fElementQName, fAttributes, null);
  294. }
  295. }
  296. if (DEBUG_CONTENT_SCANNING) System.out.println("<<< scanStartElement(): "+empty);
  297. return empty;
  298. } // scanStartElement():boolean
  299. /**
  300. * Scans the name of an element in a start or empty tag.
  301. *
  302. * @see #scanStartElement()
  303. */
  304. protected void scanStartElementName ()
  305. throws IOException, XNIException {
  306. // Note: namespace processing is on by default
  307. fEntityScanner.scanQName(fElementQName);
  308. // Must skip spaces here because the DTD scanner
  309. // would consume them at the end of the external subset.
  310. fSawSpace = fEntityScanner.skipSpaces();
  311. } // scanStartElementName()
  312. /**
  313. * Scans the remainder of a start or empty tag after the element name.
  314. *
  315. * @see #scanStartElement
  316. * @return True if element is empty.
  317. */
  318. protected boolean scanStartElementAfterName()
  319. throws IOException, XNIException {
  320. // REVISIT - [Q] Why do we need this temp variable? -- mrglavas
  321. String rawname = fElementQName.rawname;
  322. if (fBindNamespaces) {
  323. fNamespaceContext.pushContext();
  324. if (fScannerState == SCANNER_STATE_ROOT_ELEMENT) {
  325. if (fPerformValidation) {
  326. fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
  327. "MSG_GRAMMAR_NOT_FOUND",
  328. new Object[]{ rawname},
  329. XMLErrorReporter.SEVERITY_ERROR);
  330. if (fDoctypeName == null || !fDoctypeName.equals(rawname)) {
  331. fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN,
  332. "RootElementTypeMustMatchDoctypedecl",
  333. new Object[]{fDoctypeName, rawname},
  334. XMLErrorReporter.SEVERITY_ERROR);
  335. }
  336. }
  337. }
  338. }
  339. // push element stack
  340. fCurrentElement = fElementStack.pushElement(fElementQName);
  341. // attributes
  342. boolean empty = false;
  343. fAttributes.removeAllAttributes();
  344. do {
  345. // end tag?
  346. int c = fEntityScanner.peekChar();
  347. if (c == '>') {
  348. fEntityScanner.scanChar();
  349. break;
  350. }
  351. else if (c == '/') {
  352. fEntityScanner.scanChar();
  353. if (!fEntityScanner.skipChar('>')) {
  354. reportFatalError("ElementUnterminated",
  355. new Object[]{rawname});
  356. }
  357. empty = true;
  358. break;
  359. }
  360. else if (!isValidNameStartChar(c) || !fSawSpace) {
  361. reportFatalError("ElementUnterminated", new Object[]{rawname});
  362. }
  363. // attributes
  364. scanAttribute(fAttributes);
  365. // spaces
  366. fSawSpace = fEntityScanner.skipSpaces();
  367. } while (true);
  368. if (fBindNamespaces) {
  369. // REVISIT: is it required? forbit xmlns prefix for element
  370. if (fElementQName.prefix == XMLSymbols.PREFIX_XMLNS) {
  371. fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
  372. "ElementXMLNSPrefix",
  373. new Object[]{fElementQName.rawname},
  374. XMLErrorReporter.SEVERITY_FATAL_ERROR);
  375. }
  376. // bind the element
  377. String prefix = fElementQName.prefix != null
  378. ? fElementQName.prefix : XMLSymbols.EMPTY_STRING;
  379. // assign uri to the element
  380. fElementQName.uri = fNamespaceContext.getURI(prefix);
  381. // make sure that object in the element stack is updated as well
  382. fCurrentElement.uri = fElementQName.uri;
  383. if (fElementQName.prefix == null && fElementQName.uri != null) {
  384. fElementQName.prefix = XMLSymbols.EMPTY_STRING;
  385. // making sure that the object in the element stack is updated too.
  386. fCurrentElement.prefix = XMLSymbols.EMPTY_STRING;
  387. }
  388. if (fElementQName.prefix != null && fElementQName.uri == null) {
  389. fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
  390. "ElementPrefixUnbound",
  391. new Object[]{fElementQName.prefix, fElementQName.rawname},
  392. XMLErrorReporter.SEVERITY_FATAL_ERROR);
  393. }
  394. // bind attributes (xmlns are already bound bellow)
  395. int length = fAttributes.getLength();
  396. // fLength = 0; //initialize structure
  397. for (int i = 0; i < length; i++) {
  398. fAttributes.getName(i, fAttributeQName);
  399. String aprefix = fAttributeQName.prefix != null
  400. ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING;
  401. String uri = fNamespaceContext.getURI(aprefix);
  402. // REVISIT: try removing the first "if" and see if it is faster.
  403. //
  404. if (fAttributeQName.uri != null && fAttributeQName.uri == uri) {
  405. // checkDuplicates(fAttributeQName, fAttributes);
  406. continue;
  407. }
  408. if (aprefix != XMLSymbols.EMPTY_STRING) {
  409. fAttributeQName.uri = uri;
  410. if (uri == null) {
  411. fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
  412. "AttributePrefixUnbound",
  413. new Object[]{fElementQName.rawname,fAttributeQName.rawname,aprefix},
  414. XMLErrorReporter.SEVERITY_FATAL_ERROR);
  415. }
  416. fAttributes.setURI(i, uri);
  417. // checkDuplicates(fAttributeQName, fAttributes);
  418. }
  419. }
  420. if (length > 1) {
  421. QName name = fAttributes.checkDuplicatesNS();
  422. if (name != null) {
  423. if (name.uri != null) {
  424. fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
  425. "AttributeNSNotUnique",
  426. new Object[]{fElementQName.rawname, name.localpart, name.uri},
  427. XMLErrorReporter.SEVERITY_FATAL_ERROR);
  428. }
  429. else {
  430. fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
  431. "AttributeNotUnique",
  432. new Object[]{fElementQName.rawname, name.rawname},
  433. XMLErrorReporter.SEVERITY_FATAL_ERROR);
  434. }
  435. }
  436. }
  437. }
  438. // call handler
  439. if (fDocumentHandler != null) {
  440. if (empty) {
  441. //decrease the markup depth..
  442. fMarkupDepth--;
  443. // check that this element was opened in the same entity
  444. if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) {
  445. reportFatalError("ElementEntityMismatch",
  446. new Object[]{fCurrentElement.rawname});
  447. }
  448. fDocumentHandler.emptyElement(fElementQName, fAttributes, null);
  449. if (fBindNamespaces) {
  450. fNamespaceContext.popContext();
  451. }
  452. //pop the element off the stack..
  453. fElementStack.popElement(fElementQName);
  454. } else {
  455. fDocumentHandler.startElement(fElementQName, fAttributes, null);
  456. }
  457. }
  458. if (DEBUG_CONTENT_SCANNING) System.out.println("<<< scanStartElementAfterName(): "+empty);
  459. return empty;
  460. } // scanStartElementAfterName()
  461. /**
  462. * Scans an attribute.
  463. * <p>
  464. * <pre>
  465. * [41] Attribute ::= Name Eq AttValue
  466. * </pre>
  467. * <p>
  468. * <strong>Note:</strong> This method assumes that the next
  469. * character on the stream is the first character of the attribute
  470. * name.
  471. * <p>
  472. * <strong>Note:</strong> This method uses the fAttributeQName and
  473. * fQName variables. The contents of these variables will be
  474. * destroyed.
  475. *
  476. * @param attributes The attributes list for the scanned attribute.
  477. */
  478. protected void scanAttribute(XMLAttributesImpl attributes)
  479. throws IOException, XNIException {
  480. if (DEBUG_CONTENT_SCANNING) System.out.println(">>> scanAttribute()");
  481. // name
  482. fEntityScanner.scanQName(fAttributeQName);
  483. // equals
  484. fEntityScanner.skipSpaces();
  485. if (!fEntityScanner.skipChar('=')) {
  486. reportFatalError("EqRequiredInAttribute",
  487. new Object[]{fCurrentElement.rawname,fAttributeQName.rawname});
  488. }
  489. fEntityScanner.skipSpaces();
  490. // content
  491. int attrIndex;
  492. if (fBindNamespaces) {
  493. attrIndex = attributes.getLength();
  494. attributes.addAttributeNS(fAttributeQName, XMLSymbols.fCDATASymbol, null);
  495. }
  496. else {
  497. int oldLen = attributes.getLength();
  498. attrIndex = attributes.addAttribute(fAttributeQName, XMLSymbols.fCDATASymbol, null);
  499. // WFC: Unique Att Spec
  500. if (oldLen == attributes.getLength()) {
  501. reportFatalError("AttributeNotUnique",
  502. new Object[]{fCurrentElement.rawname,
  503. fAttributeQName.rawname});
  504. }
  505. }
  506. //REVISIT: one more case needs to be included: external PE and standalone is no
  507. boolean isVC = fHasExternalDTD && !fStandalone;
  508. scanAttributeValue(this.fTempString, fTempString2,
  509. fAttributeQName.rawname, isVC,
  510. fCurrentElement.rawname);
  511. String value = fTempString.toString();
  512. attributes.setValue(attrIndex, value);
  513. attributes.setNonNormalizedValue(attrIndex, fTempString2.toString());
  514. attributes.setSpecified(attrIndex, true);
  515. // record namespace declarations if any.
  516. if (fBindNamespaces) {
  517. String localpart = fAttributeQName.localpart;
  518. String prefix = fAttributeQName.prefix != null
  519. ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING;
  520. // when it's of form xmlns="..." or xmlns:prefix="...",
  521. // it's a namespace declaration. but prefix:xmlns="..." isn't.
  522. if (prefix == XMLSymbols.PREFIX_XMLNS ||
  523. prefix == XMLSymbols.EMPTY_STRING && localpart == XMLSymbols.PREFIX_XMLNS) {
  524. // get the internalized value of this attribute
  525. String uri = fSymbolTable.addSymbol(value);
  526. // 1. "xmlns" can't be bound to any namespace
  527. if (prefix == XMLSymbols.PREFIX_XMLNS && localpart == XMLSymbols.PREFIX_XMLNS) {
  528. fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
  529. "CantBindXMLNS",
  530. new Object[]{fAttributeQName},
  531. XMLErrorReporter.SEVERITY_FATAL_ERROR);
  532. }
  533. // 2. the namespace for "xmlns" can't be bound to any prefix
  534. if (uri == NamespaceContext.XMLNS_URI) {
  535. fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
  536. "CantBindXMLNS",
  537. new Object[]{fAttributeQName},
  538. XMLErrorReporter.SEVERITY_FATAL_ERROR);
  539. }
  540. // 3. "xml" can't be bound to any other namespace than it's own
  541. if (localpart == XMLSymbols.PREFIX_XML) {
  542. if (uri != NamespaceContext.XML_URI) {
  543. fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
  544. "CantBindXML",
  545. new Object[]{fAttributeQName},
  546. XMLErrorReporter.SEVERITY_FATAL_ERROR);
  547. }
  548. }
  549. // 4. the namespace for "xml" can't be bound to any other prefix
  550. else {
  551. if (uri ==NamespaceContext.XML_URI) {
  552. fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
  553. "CantBindXML",
  554. new Object[]{fAttributeQName},
  555. XMLErrorReporter.SEVERITY_FATAL_ERROR);
  556. }
  557. }
  558. prefix = localpart != XMLSymbols.PREFIX_XMLNS ? localpart : XMLSymbols.EMPTY_STRING;
  559. // http://www.w3.org/TR/1999/REC-xml-names-19990114/#dt-prefix
  560. // We should only report an error if there is a prefix,
  561. // that is, the local part is not "xmlns". -SG
  562. if (uri == XMLSymbols.EMPTY_STRING && localpart != XMLSymbols.PREFIX_XMLNS) {
  563. fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
  564. "EmptyPrefixedAttName",
  565. new Object[]{fAttributeQName},
  566. XMLErrorReporter.SEVERITY_FATAL_ERROR);
  567. }
  568. // declare prefix in context
  569. fNamespaceContext.declarePrefix(prefix, uri.length() != 0 ? uri : null);
  570. // bind namespace attribute to a namespace
  571. attributes.setURI(attrIndex, fNamespaceContext.getURI(XMLSymbols.PREFIX_XMLNS));
  572. }
  573. else {
  574. // attempt to bind attribute
  575. if (fAttributeQName.prefix != null) {
  576. attributes.setURI(attrIndex, fNamespaceContext.getURI(fAttributeQName.prefix));
  577. }
  578. }
  579. }
  580. if (DEBUG_CONTENT_SCANNING) System.out.println("<<< scanAttribute()");
  581. } // scanAttribute(XMLAttributes)
  582. /**
  583. * Scans an end element.
  584. * <p>
  585. * <pre>
  586. * [42] ETag ::= '</' Name S? '>'
  587. * </pre>
  588. * <p>
  589. * <strong>Note:</strong> This method uses the fElementQName variable.
  590. * The contents of this variable will be destroyed. The caller should
  591. * copy the needed information out of this variable before calling
  592. * this method.
  593. *
  594. * @return The element depth.
  595. */
  596. protected int scanEndElement() throws IOException, XNIException {
  597. if (DEBUG_CONTENT_SCANNING) System.out.println(">>> scanEndElement()");
  598. // pop context
  599. fElementStack.popElement(fElementQName) ;
  600. // Take advantage of the fact that next string _should_ be "fElementQName.rawName",
  601. //In scanners most of the time is consumed on checks done for XML characters, we can
  602. // optimize on it and avoid the checks done for endElement,
  603. //we will also avoid symbol table lookup - neeraj.bajaj@sun.com
  604. // this should work both for namespace processing true or false...
  605. //REVISIT: if the string is not the same as expected.. we need to do better error handling..
  606. //We can skip this for now... In any case if the string doesn't match -- document is not well formed.
  607. if (!fEntityScanner.skipString(fElementQName.rawname)) {
  608. reportFatalError("ETagRequired", new Object[]{fElementQName.rawname});
  609. }
  610. // end
  611. fEntityScanner.skipSpaces();
  612. if (!fEntityScanner.skipChar('>')) {
  613. reportFatalError("ETagUnterminated",
  614. new Object[]{fElementQName.rawname});
  615. }
  616. fMarkupDepth--;
  617. //we have increased the depth for two markup "<" characters
  618. fMarkupDepth--;
  619. // check that this element was opened in the same entity
  620. if (fMarkupDepth < fEntityStack[fEntityDepth - 1]) {
  621. reportFatalError("ElementEntityMismatch",
  622. new Object[]{fCurrentElement.rawname});
  623. }
  624. // call handler
  625. if (fDocumentHandler != null ) {
  626. fDocumentHandler.endElement(fElementQName, null);
  627. if (fBindNamespaces) {
  628. fNamespaceContext.popContext();
  629. }
  630. }
  631. return fMarkupDepth;
  632. } // scanEndElement():int
  633. public void reset(XMLComponentManager componentManager)
  634. throws XMLConfigurationException {
  635. super.reset(componentManager);
  636. fPerformValidation = false;
  637. fBindNamespaces = false;
  638. }
  639. /** Creates a content dispatcher. */
  640. protected Dispatcher createContentDispatcher() {
  641. return new NSContentDispatcher();
  642. } // createContentDispatcher():Dispatcher
  643. /**
  644. * Dispatcher to handle content scanning.
  645. */
  646. protected final class NSContentDispatcher
  647. extends ContentDispatcher {
  648. /**
  649. * Scan for root element hook. This method is a hook for
  650. * subclasses to add code that handles scanning for the root
  651. * element. This method will also attempt to remove DTD validator
  652. * from the pipeline, if there is no DTD grammar. If DTD validator
  653. * is no longer in the pipeline bind namespaces in the scanner.
  654. *
  655. *
  656. * @return True if the caller should stop and return true which
  657. * allows the scanner to switch to a new scanning
  658. * dispatcher. A return value of false indicates that
  659. * the content dispatcher should continue as normal.
  660. */
  661. protected boolean scanRootElementHook()
  662. throws IOException, XNIException {
  663. if (fExternalSubsetResolver != null && !fSeenDoctypeDecl
  664. && !fDisallowDoctype && (fValidation || fLoadExternalDTD)) {
  665. scanStartElementName();
  666. resolveExternalSubsetAndRead();
  667. reconfigurePipeline();
  668. if (scanStartElementAfterName()) {
  669. setScannerState(SCANNER_STATE_TRAILING_MISC);
  670. setDispatcher(fTrailingMiscDispatcher);
  671. return true;
  672. }
  673. }
  674. else {
  675. reconfigurePipeline();
  676. if (scanStartElement()) {
  677. setScannerState(SCANNER_STATE_TRAILING_MISC);
  678. setDispatcher(fTrailingMiscDispatcher);
  679. return true;
  680. }
  681. }
  682. return false;
  683. } // scanRootElementHook():boolean
  684. /**
  685. * Re-configures pipeline by removing the DTD validator
  686. * if no DTD grammar exists. If no validator exists in the
  687. * pipeline or there is no DTD grammar, namespace binding
  688. * is performed by the scanner in the enclosing class.
  689. */
  690. private void reconfigurePipeline() {
  691. if (fDTDValidator == null) {
  692. fBindNamespaces = true;
  693. }
  694. else if (!fDTDValidator.hasGrammar()) {
  695. fBindNamespaces = true;
  696. fPerformValidation = fDTDValidator.validate();
  697. // re-configure pipeline
  698. XMLDocumentSource source = fDTDValidator.getDocumentSource();
  699. XMLDocumentHandler handler = fDTDValidator.getDocumentHandler();
  700. source.setDocumentHandler(handler);
  701. if (handler != null)
  702. handler.setDocumentSource(source);
  703. fDTDValidator.setDocumentSource(null);
  704. fDTDValidator.setDocumentHandler(null);
  705. }
  706. } // reconfigurePipeline()
  707. }
  708. } // class XMLNSDocumentScannerImpl