1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 2000-2004 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) 2001, 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.parsers;
  58. import java.io.StringReader;
  59. import java.util.Locale;
  60. import java.util.Stack;
  61. import java.util.StringTokenizer;
  62. import java.util.Vector;
  63. import java.util.Locale;
  64. import com.sun.org.apache.xerces.internal.dom.DOMErrorImpl;
  65. import com.sun.org.apache.xerces.internal.dom.DOMMessageFormatter;
  66. import com.sun.org.apache.xerces.internal.dom.DOMStringListImpl;
  67. import org.w3c.dom.DOMError;
  68. import com.sun.org.apache.xerces.internal.impl.Constants;
  69. import com.sun.org.apache.xerces.internal.util.DOMEntityResolverWrapper;
  70. import com.sun.org.apache.xerces.internal.util.DOMErrorHandlerWrapper;
  71. import com.sun.org.apache.xerces.internal.util.SymbolTable;
  72. import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarPool;
  73. import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
  74. import com.sun.org.apache.xerces.internal.xni.parser.XMLEntityResolver;
  75. import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
  76. import com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration;
  77. import org.w3c.dom.DOMConfiguration;
  78. import org.w3c.dom.DOMErrorHandler;
  79. import org.w3c.dom.DOMException;
  80. import org.w3c.dom.Document;
  81. import org.w3c.dom.DOMStringList;
  82. import org.w3c.dom.Node;
  83. import org.w3c.dom.ls.LSException;
  84. import org.w3c.dom.ls.LSParser;
  85. import org.w3c.dom.ls.LSParserFilter;
  86. import org.w3c.dom.ls.LSResourceResolver;
  87. import org.w3c.dom.ls.LSInput;
  88. /**
  89. * This is Xerces DOM Builder class. It uses the abstract DOM
  90. * parser with a document scanner, a dtd scanner, and a validator, as
  91. * well as a grammar pool.
  92. *
  93. * @author Pavani Mukthipudi, Sun Microsystems Inc.
  94. * @author Elena Litani, IBM
  95. * @author Rahul Srivastava, Sun Microsystems Inc.
  96. * @version $Id: DOMParserImpl.java,v 1.25 2004/04/23 16:06:10 mrglavas Exp $
  97. */
  98. public class DOMParserImpl
  99. extends AbstractDOMParser implements LSParser, DOMConfiguration {
  100. // SAX & Xerces feature ids
  101. /** Feature identifier: namespaces. */
  102. protected static final String NAMESPACES =
  103. Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE;
  104. /** Feature id: validation. */
  105. protected static final String VALIDATION_FEATURE =
  106. Constants.SAX_FEATURE_PREFIX+Constants.VALIDATION_FEATURE;
  107. /** XML Schema validation */
  108. protected static final String XMLSCHEMA =
  109. Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE;
  110. /** Dynamic validation */
  111. protected static final String DYNAMIC_VALIDATION =
  112. Constants.XERCES_FEATURE_PREFIX + Constants.DYNAMIC_VALIDATION_FEATURE;
  113. /** Feature identifier: expose schema normalized value */
  114. protected static final String NORMALIZE_DATA =
  115. Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_NORMALIZED_VALUE;
  116. /** Feature identifier: disallow docType Decls. */
  117. protected static final String DISALLOW_DOCTYPE_DECL_FEATURE =
  118. Constants.XERCES_FEATURE_PREFIX + Constants.DISALLOW_DOCTYPE_DECL_FEATURE;
  119. // internal properties
  120. protected static final String SYMBOL_TABLE =
  121. Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
  122. protected static final String PSVI_AUGMENT =
  123. Constants.XERCES_FEATURE_PREFIX +Constants.SCHEMA_AUGMENT_PSVI;
  124. Thread currentThread = null;
  125. //
  126. // Data
  127. //
  128. // REVISIT: this value should be null by default and should be set during creation of
  129. // LSParser
  130. protected String fSchemaType = null;
  131. protected boolean fBusy = false;
  132. protected final static boolean DEBUG = false;
  133. private Vector fSchemaLocations = new Vector ();
  134. private String fSchemaLocation = null;
  135. private DOMStringList fRecognizedParameters;
  136. private boolean abortNow = false;
  137. //
  138. // Constructors
  139. //
  140. /**
  141. * Constructs a DOM Builder using the standard parser configuration.
  142. */
  143. public DOMParserImpl (String configuration, String schemaType) {
  144. this (
  145. (XMLParserConfiguration) ObjectFactory.createObject (
  146. "com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration",
  147. configuration));
  148. if (schemaType != null) {
  149. if (schemaType.equals (Constants.NS_DTD)) {
  150. fConfiguration.setFeature (
  151. Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE,
  152. false);
  153. fConfiguration.setProperty (
  154. Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_LANGUAGE,
  155. Constants.NS_DTD);
  156. fSchemaType = Constants.NS_DTD;
  157. }
  158. else if (schemaType.equals (Constants.NS_XMLSCHEMA)) {
  159. // XML Schem validation
  160. fConfiguration.setProperty (
  161. Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_LANGUAGE,
  162. Constants.NS_XMLSCHEMA);
  163. }
  164. }
  165. }
  166. /**
  167. * Constructs a DOM Builder using the specified parser configuration.
  168. */
  169. public DOMParserImpl (XMLParserConfiguration config) {
  170. super (config);
  171. // add recognized features
  172. final String[] domRecognizedFeatures = {
  173. Constants.DOM_CANONICAL_FORM,
  174. Constants.DOM_CDATA_SECTIONS,
  175. Constants.DOM_CHARSET_OVERRIDES_XML_ENCODING,
  176. Constants.DOM_INFOSET,
  177. Constants.DOM_NAMESPACE_DECLARATIONS,
  178. Constants.DOM_SPLIT_CDATA,
  179. Constants.DOM_SUPPORTED_MEDIATYPES_ONLY,
  180. Constants.DOM_CERTIFIED,
  181. Constants.DOM_WELLFORMED,
  182. Constants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS,
  183. };
  184. fConfiguration.addRecognizedFeatures (domRecognizedFeatures);
  185. // turn off deferred DOM
  186. fConfiguration.setFeature (DEFER_NODE_EXPANSION, false);
  187. // Set values so that the value of the
  188. // infoset parameter is true (its default value).
  189. //
  190. // true: namespace-declarations, well-formed,
  191. // element-content-whitespace, comments, namespaces
  192. //
  193. // false: validate-if-schema, entities,
  194. // datatype-normalization, cdata-sections
  195. fConfiguration.setFeature(Constants.DOM_NAMESPACE_DECLARATIONS, true);
  196. fConfiguration.setFeature(Constants.DOM_WELLFORMED, true);
  197. fConfiguration.setFeature(INCLUDE_COMMENTS_FEATURE, true);
  198. fConfiguration.setFeature(INCLUDE_IGNORABLE_WHITESPACE, true);
  199. fConfiguration.setFeature(NAMESPACES, true);
  200. fConfiguration.setFeature(DYNAMIC_VALIDATION, false);
  201. fConfiguration.setFeature(CREATE_ENTITY_REF_NODES, false);
  202. fConfiguration.setFeature(NORMALIZE_DATA, false);
  203. fConfiguration.setFeature(CREATE_CDATA_NODES_FEATURE, false);
  204. // set other default values
  205. fConfiguration.setFeature (Constants.DOM_CANONICAL_FORM, false);
  206. fConfiguration.setFeature (Constants.DOM_CHARSET_OVERRIDES_XML_ENCODING, true);
  207. fConfiguration.setFeature (Constants.DOM_SPLIT_CDATA, true);
  208. fConfiguration.setFeature (Constants.DOM_SUPPORTED_MEDIATYPES_ONLY, false);
  209. fConfiguration.setFeature (Constants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS, true);
  210. // REVISIT: by default Xerces assumes that input is certified.
  211. // default is different from the one specified in the DOM spec
  212. fConfiguration.setFeature (Constants.DOM_CERTIFIED, true);
  213. // Xerces datatype-normalization feature is on by default
  214. fConfiguration.setFeature( NORMALIZE_DATA, false );
  215. } // <init>(XMLParserConfiguration)
  216. /**
  217. * Constructs a DOM Builder using the specified symbol table.
  218. */
  219. public DOMParserImpl(SymbolTable symbolTable) {
  220. this(
  221. (XMLParserConfiguration) ObjectFactory.createObject(
  222. "com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration",
  223. "com.sun.org.apache.xerces.internal.parsers.XIncludeParserConfiguration"));
  224. fConfiguration.setProperty(
  225. Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY,
  226. symbolTable);
  227. } // <init>(SymbolTable)
  228. /**
  229. * Constructs a DOM Builder using the specified symbol table and
  230. * grammar pool.
  231. */
  232. public DOMParserImpl(SymbolTable symbolTable, XMLGrammarPool grammarPool) {
  233. this(
  234. (XMLParserConfiguration) ObjectFactory.createObject(
  235. "com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration",
  236. "com.sun.org.apache.xerces.internal.parsers.XIncludeParserConfiguration"));
  237. fConfiguration.setProperty(
  238. Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY,
  239. symbolTable);
  240. fConfiguration.setProperty(
  241. Constants.XERCES_PROPERTY_PREFIX
  242. + Constants.XMLGRAMMAR_POOL_PROPERTY,
  243. grammarPool);
  244. }
  245. /**
  246. * Resets the parser state.
  247. *
  248. * @throws SAXException Thrown on initialization error.
  249. */
  250. public void reset() {
  251. super.reset();
  252. // DOM Filter
  253. if (fSkippedElemStack!=null) {
  254. fSkippedElemStack.removeAllElements();
  255. }
  256. fSchemaLocations.clear();
  257. fRejectedElement.clear();
  258. fFilterReject = false;
  259. fSchemaType = null;
  260. } // reset()
  261. //
  262. // DOMParser methods
  263. //
  264. public DOMConfiguration getDomConfig (){
  265. return this;
  266. }
  267. /**
  268. * When the application provides a filter, the parser will call out to
  269. * the filter at the completion of the construction of each
  270. * <code>Element</code> node. The filter implementation can choose to
  271. * remove the element from the document being constructed (unless the
  272. * element is the document element) or to terminate the parse early. If
  273. * the document is being validated when it's loaded the validation
  274. * happens before the filter is called.
  275. */
  276. public LSParserFilter getFilter() {
  277. return fDOMFilter;
  278. }
  279. /**
  280. * When the application provides a filter, the parser will call out to
  281. * the filter at the completion of the construction of each
  282. * <code>Element</code> node. The filter implementation can choose to
  283. * remove the element from the document being constructed (unless the
  284. * element is the document element) or to terminate the parse early. If
  285. * the document is being validated when it's loaded the validation
  286. * happens before the filter is called.
  287. */
  288. public void setFilter(LSParserFilter filter) {
  289. fDOMFilter = filter;
  290. if (fSkippedElemStack == null) {
  291. fSkippedElemStack = new Stack();
  292. }
  293. }
  294. /**
  295. * Set parameters and properties
  296. */
  297. public void setParameter (String name, Object value) throws DOMException {
  298. // set features
  299. if(value instanceof Boolean){
  300. boolean state = ((Boolean)value).booleanValue ();
  301. try {
  302. if (name.equalsIgnoreCase (Constants.DOM_COMMENTS)) {
  303. fConfiguration.setFeature (INCLUDE_COMMENTS_FEATURE, state);
  304. }
  305. else if (name.equalsIgnoreCase (Constants.DOM_DATATYPE_NORMALIZATION)) {
  306. fConfiguration.setFeature (NORMALIZE_DATA, state);
  307. }
  308. else if (name.equalsIgnoreCase (Constants.DOM_ENTITIES)) {
  309. fConfiguration.setFeature (CREATE_ENTITY_REF_NODES, state);
  310. }
  311. else if (name.equalsIgnoreCase (Constants.DOM_DISALLOW_DOCTYPE)) {
  312. fConfiguration.setFeature (DISALLOW_DOCTYPE_DECL_FEATURE, state);
  313. }
  314. else if (name.equalsIgnoreCase (Constants.DOM_SUPPORTED_MEDIATYPES_ONLY)
  315. || name.equalsIgnoreCase(Constants.DOM_NORMALIZE_CHARACTERS)
  316. || name.equalsIgnoreCase (Constants.DOM_CHECK_CHAR_NORMALIZATION)
  317. || name.equalsIgnoreCase (Constants.DOM_CANONICAL_FORM)) {
  318. if (state) { // true is not supported
  319. String msg =
  320. DOMMessageFormatter.formatMessage (
  321. DOMMessageFormatter.DOM_DOMAIN,
  322. "FEATURE_NOT_SUPPORTED",
  323. new Object[] { name });
  324. throw new DOMException (DOMException.NOT_SUPPORTED_ERR, msg);
  325. }
  326. // setting those features to false is no-op
  327. }
  328. else if (name.equalsIgnoreCase (Constants.DOM_NAMESPACES)) {
  329. fConfiguration.setFeature (NAMESPACES, state);
  330. }
  331. else if (name.equalsIgnoreCase (Constants.DOM_INFOSET)) {
  332. // Setting false has no effect.
  333. if (state) {
  334. // true: namespaces, comments, element-content-whitespace
  335. fConfiguration.setFeature(NAMESPACES, true);
  336. fConfiguration.setFeature(INCLUDE_COMMENTS_FEATURE, true);
  337. fConfiguration.setFeature(INCLUDE_IGNORABLE_WHITESPACE, true);
  338. // false: validate-if-schema, entities,
  339. // datatype-normalization, cdata-sections
  340. fConfiguration.setFeature(DYNAMIC_VALIDATION, false);
  341. fConfiguration.setFeature(CREATE_ENTITY_REF_NODES, false);
  342. fConfiguration.setFeature(NORMALIZE_DATA, false);
  343. fConfiguration.setFeature(CREATE_CDATA_NODES_FEATURE, false);
  344. }
  345. }
  346. else if (name.equalsIgnoreCase(Constants.DOM_CDATA_SECTIONS)) {
  347. fConfiguration.setFeature(CREATE_CDATA_NODES_FEATURE, state);
  348. }
  349. else if (name.equalsIgnoreCase (Constants.DOM_NAMESPACE_DECLARATIONS)
  350. || name.equalsIgnoreCase (Constants.DOM_WELLFORMED)
  351. || name.equalsIgnoreCase (Constants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS)) {
  352. if (!state) { // false is not supported
  353. String msg =
  354. DOMMessageFormatter.formatMessage (
  355. DOMMessageFormatter.DOM_DOMAIN,
  356. "FEATURE_NOT_SUPPORTED",
  357. new Object[] { name });
  358. throw new DOMException (DOMException.NOT_SUPPORTED_ERR, msg);
  359. }
  360. // setting these features to true is no-op
  361. // REVISIT: implement "namespace-declaration" feature
  362. }
  363. else if (name.equalsIgnoreCase (Constants.DOM_VALIDATE)) {
  364. fConfiguration.setFeature (VALIDATION_FEATURE, state);
  365. if (fSchemaType != Constants.NS_DTD) {
  366. fConfiguration.setFeature (XMLSCHEMA, state);
  367. }
  368. if (state){
  369. fConfiguration.setFeature (DYNAMIC_VALIDATION, false);
  370. }
  371. }
  372. else if (name.equalsIgnoreCase (Constants.DOM_VALIDATE_IF_SCHEMA)) {
  373. fConfiguration.setFeature (DYNAMIC_VALIDATION, state);
  374. // Note: validation and dynamic validation are mutually exclusive
  375. if (state){
  376. fConfiguration.setFeature(VALIDATION_FEATURE, false);
  377. }
  378. }
  379. else if (name.equalsIgnoreCase (Constants.DOM_ELEMENT_CONTENT_WHITESPACE)) {
  380. fConfiguration.setFeature (INCLUDE_IGNORABLE_WHITESPACE, state);
  381. }
  382. else if (name.equalsIgnoreCase (Constants.DOM_PSVI)){
  383. //XSModel - turn on PSVI augmentation
  384. fConfiguration.setFeature(PSVI_AUGMENT, true);
  385. fConfiguration.setProperty(DOCUMENT_CLASS_NAME,
  386. "com.sun.org.apache.xerces.internal.dom.PSVIDocumentImpl");
  387. }
  388. else {
  389. // Constants.DOM_CHARSET_OVERRIDES_XML_ENCODING feature,
  390. // Constants.DOM_SPLIT_CDATA feature,
  391. // or any Xerces feature
  392. fConfiguration.setFeature (name.toLowerCase(Locale.ENGLISH), state);
  393. }
  394. }
  395. catch (XMLConfigurationException e) {
  396. String msg =
  397. DOMMessageFormatter.formatMessage (
  398. DOMMessageFormatter.DOM_DOMAIN,
  399. "FEATURE_NOT_FOUND",
  400. new Object[] { name });
  401. throw new DOMException (DOMException.NOT_FOUND_ERR, msg);
  402. }
  403. }
  404. else { // set properties
  405. if (name.equalsIgnoreCase (Constants.DOM_ERROR_HANDLER)) {
  406. if (value instanceof DOMErrorHandler || value == null) {
  407. try {
  408. fErrorHandler = new DOMErrorHandlerWrapper ((DOMErrorHandler) value);
  409. fConfiguration.setProperty (ERROR_HANDLER, fErrorHandler);
  410. }
  411. catch (XMLConfigurationException e) {}
  412. }
  413. else {
  414. // REVISIT: type mismatch
  415. String msg =
  416. DOMMessageFormatter.formatMessage (
  417. DOMMessageFormatter.DOM_DOMAIN,
  418. "TYPE_MISMATCH_ERR",
  419. new Object[] { name });
  420. throw new DOMException (DOMException.NOT_SUPPORTED_ERR, msg);
  421. }
  422. }
  423. else if (name.equalsIgnoreCase (Constants.DOM_RESOURCE_RESOLVER)) {
  424. if (value instanceof LSResourceResolver || value == null) {
  425. try {
  426. fConfiguration.setProperty (ENTITY_RESOLVER, new DOMEntityResolverWrapper ((LSResourceResolver) value));
  427. }
  428. catch (XMLConfigurationException e) {}
  429. }
  430. else {
  431. // REVISIT: type mismatch
  432. String msg =
  433. DOMMessageFormatter.formatMessage (
  434. DOMMessageFormatter.DOM_DOMAIN,
  435. "TYPE_MISMATCH_ERR",
  436. new Object[] { name });
  437. throw new DOMException (DOMException.NOT_SUPPORTED_ERR, msg);
  438. }
  439. }
  440. else if (name.equalsIgnoreCase (Constants.DOM_SCHEMA_LOCATION)) {
  441. if (value instanceof String || value == null) {
  442. try {
  443. if (value == null) {
  444. fConfiguration.setProperty (
  445. Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_SOURCE,
  446. null);
  447. }
  448. else if (fSchemaType == Constants.NS_XMLSCHEMA) {
  449. fSchemaLocation = (String)value;
  450. // map DOM schema-location to JAXP schemaSource property
  451. // tokenize location string
  452. StringTokenizer t = new StringTokenizer (fSchemaLocation, " \n\t\r");
  453. if (t.hasMoreTokens ()){
  454. fSchemaLocations.clear ();
  455. fSchemaLocations.add (t.nextToken ());
  456. while (t.hasMoreTokens ()) {
  457. fSchemaLocations.add (t.nextToken ());
  458. }
  459. fConfiguration.setProperty (
  460. Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_SOURCE,
  461. fSchemaLocations.toArray ());
  462. }
  463. else {
  464. fConfiguration.setProperty (
  465. Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_SOURCE,
  466. value);
  467. }
  468. }
  469. else {
  470. // REVISIT: allow pre-parsing DTD grammars
  471. String msg =
  472. DOMMessageFormatter.formatMessage (
  473. DOMMessageFormatter.DOM_DOMAIN,
  474. "FEATURE_NOT_SUPPORTED",
  475. new Object[] { name });
  476. throw new DOMException (DOMException.NOT_SUPPORTED_ERR, msg);
  477. }
  478. }
  479. catch (XMLConfigurationException e) {}
  480. }
  481. else {
  482. // REVISIT: type mismatch
  483. String msg =
  484. DOMMessageFormatter.formatMessage (
  485. DOMMessageFormatter.DOM_DOMAIN,
  486. "TYPE_MISMATCH_ERR",
  487. new Object[] { name });
  488. throw new DOMException (DOMException.NOT_SUPPORTED_ERR, msg);
  489. }
  490. }
  491. else if (name.equalsIgnoreCase (Constants.DOM_SCHEMA_TYPE)) {
  492. if (value instanceof String || value == null) {
  493. try {
  494. if (value == null) {
  495. // turn off schema feature
  496. fConfiguration.setFeature (
  497. Constants.XERCES_FEATURE_PREFIX
  498. + Constants.SCHEMA_VALIDATION_FEATURE,
  499. false);
  500. // map to JAXP schemaLanguage
  501. fConfiguration.setProperty ( Constants.JAXP_PROPERTY_PREFIX
  502. + Constants.SCHEMA_LANGUAGE,
  503. null);
  504. fSchemaType = null;
  505. }
  506. else if (value.equals (Constants.NS_XMLSCHEMA)) {
  507. // turn on schema feature
  508. fConfiguration.setFeature (Constants.XERCES_FEATURE_PREFIX
  509. + Constants.SCHEMA_VALIDATION_FEATURE,
  510. true);
  511. // map to JAXP schemaLanguage
  512. fConfiguration.setProperty ( Constants.JAXP_PROPERTY_PREFIX
  513. + Constants.SCHEMA_LANGUAGE,
  514. Constants.NS_XMLSCHEMA);
  515. fSchemaType = Constants.NS_XMLSCHEMA;
  516. }
  517. else if (value.equals (Constants.NS_DTD)) {
  518. // turn off schema feature
  519. fConfiguration.setFeature (
  520. Constants.XERCES_FEATURE_PREFIX
  521. + Constants.SCHEMA_VALIDATION_FEATURE,
  522. false);
  523. // map to JAXP schemaLanguage
  524. fConfiguration.setProperty ( Constants.JAXP_PROPERTY_PREFIX
  525. + Constants.SCHEMA_LANGUAGE,
  526. Constants.NS_DTD);
  527. fSchemaType = Constants.NS_DTD;
  528. }
  529. }
  530. catch (XMLConfigurationException e) {}
  531. }
  532. else {
  533. String msg =
  534. DOMMessageFormatter.formatMessage (
  535. DOMMessageFormatter.DOM_DOMAIN,
  536. "TYPE_MISMATCH_ERR",
  537. new Object[] { name });
  538. throw new DOMException (DOMException.NOT_SUPPORTED_ERR, msg);
  539. }
  540. }
  541. else if (name.equalsIgnoreCase (DOCUMENT_CLASS_NAME)) {
  542. fConfiguration.setProperty (DOCUMENT_CLASS_NAME, value);
  543. }
  544. else {
  545. // REVISIT: check if this is a boolean parameter -- type mismatch should be thrown.
  546. //parameter is not recognized
  547. String msg =
  548. DOMMessageFormatter.formatMessage (
  549. DOMMessageFormatter.DOM_DOMAIN,
  550. "FEATURE_NOT_FOUND",
  551. new Object[] { name });
  552. throw new DOMException (DOMException.NOT_FOUND_ERR, msg);
  553. }
  554. }
  555. }
  556. /**
  557. * Look up the value of a feature or a property.
  558. */
  559. public Object getParameter (String name) throws DOMException {
  560. if (name.equalsIgnoreCase (Constants.DOM_COMMENTS)) {
  561. return (fConfiguration.getFeature (INCLUDE_COMMENTS_FEATURE))
  562. ? Boolean.TRUE
  563. : Boolean.FALSE;
  564. }
  565. else if (name.equalsIgnoreCase (Constants.DOM_DATATYPE_NORMALIZATION)) {
  566. return (fConfiguration.getFeature (NORMALIZE_DATA))
  567. ? Boolean.TRUE
  568. : Boolean.FALSE;
  569. }
  570. else if (name.equalsIgnoreCase (Constants.DOM_ENTITIES)) {
  571. return (fConfiguration.getFeature (CREATE_ENTITY_REF_NODES))
  572. ? Boolean.TRUE
  573. : Boolean.FALSE;
  574. }
  575. else if (name.equalsIgnoreCase (Constants.DOM_NAMESPACES)) {
  576. return (fConfiguration.getFeature (NAMESPACES))
  577. ? Boolean.TRUE
  578. : Boolean.FALSE;
  579. }
  580. else if (name.equalsIgnoreCase (Constants.DOM_VALIDATE)) {
  581. return (fConfiguration.getFeature (VALIDATION_FEATURE))
  582. ? Boolean.TRUE
  583. : Boolean.FALSE;
  584. }
  585. else if (name.equalsIgnoreCase (Constants.DOM_VALIDATE_IF_SCHEMA)) {
  586. return (fConfiguration.getFeature (DYNAMIC_VALIDATION))
  587. ? Boolean.TRUE
  588. : Boolean.FALSE;
  589. }
  590. else if (name.equalsIgnoreCase (Constants.DOM_ELEMENT_CONTENT_WHITESPACE)) {
  591. return (fConfiguration.getFeature (INCLUDE_IGNORABLE_WHITESPACE))
  592. ? Boolean.TRUE
  593. : Boolean.FALSE;
  594. }
  595. else if (name.equalsIgnoreCase (Constants.DOM_DISALLOW_DOCTYPE)) {
  596. return (fConfiguration.getFeature (DISALLOW_DOCTYPE_DECL_FEATURE))
  597. ? Boolean.TRUE
  598. : Boolean.FALSE;
  599. }
  600. else if (name.equalsIgnoreCase (Constants.DOM_INFOSET)) {
  601. // REVISIT: This is somewhat expensive to compute
  602. // but it's possible that the user has a reference
  603. // to the configuration and is changing the values
  604. // of these features directly on it.
  605. boolean infoset = fConfiguration.getFeature(NAMESPACES) &&
  606. fConfiguration.getFeature(INCLUDE_COMMENTS_FEATURE) &&
  607. fConfiguration.getFeature(INCLUDE_IGNORABLE_WHITESPACE) &&
  608. !fConfiguration.getFeature(DYNAMIC_VALIDATION) &&
  609. !fConfiguration.getFeature(CREATE_ENTITY_REF_NODES) &&
  610. !fConfiguration.getFeature(NORMALIZE_DATA) &&
  611. !fConfiguration.getFeature(CREATE_CDATA_NODES_FEATURE);
  612. return (infoset) ? Boolean.TRUE : Boolean.FALSE;
  613. }
  614. else if (name.equalsIgnoreCase(Constants.DOM_CDATA_SECTIONS)) {
  615. return (fConfiguration.getFeature(CREATE_CDATA_NODES_FEATURE))
  616. ? Boolean.TRUE : Boolean.FALSE;
  617. }
  618. else if (name.equalsIgnoreCase(Constants.DOM_CHECK_CHAR_NORMALIZATION ) ||
  619. name.equalsIgnoreCase(Constants.DOM_NORMALIZE_CHARACTERS)){
  620. return Boolean.FALSE;
  621. }
  622. else if (name.equalsIgnoreCase(Constants.DOM_NAMESPACE_DECLARATIONS)
  623. || name.equalsIgnoreCase (Constants.DOM_WELLFORMED)
  624. || name.equalsIgnoreCase (Constants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS)
  625. || name.equalsIgnoreCase (Constants.DOM_CANONICAL_FORM)
  626. || name.equalsIgnoreCase (Constants.DOM_SUPPORTED_MEDIATYPES_ONLY)
  627. || name.equalsIgnoreCase (Constants.DOM_SPLIT_CDATA)
  628. || name.equalsIgnoreCase (Constants.DOM_CHARSET_OVERRIDES_XML_ENCODING)) {
  629. return (fConfiguration.getFeature (name.toLowerCase(Locale.ENGLISH)))
  630. ? Boolean.TRUE
  631. : Boolean.FALSE;
  632. }
  633. else if (name.equalsIgnoreCase (Constants.DOM_ERROR_HANDLER)) {
  634. if (fErrorHandler != null) {
  635. return fErrorHandler.getErrorHandler ();
  636. }
  637. return null;
  638. }
  639. else if (name.equalsIgnoreCase (Constants.DOM_RESOURCE_RESOLVER)) {
  640. try {
  641. XMLEntityResolver entityResolver =
  642. (XMLEntityResolver) fConfiguration.getProperty (ENTITY_RESOLVER);
  643. if (entityResolver != null
  644. && entityResolver instanceof DOMEntityResolverWrapper) {
  645. return ((DOMEntityResolverWrapper) entityResolver).getEntityResolver ();
  646. }
  647. return null;
  648. }
  649. catch (XMLConfigurationException e) {}
  650. }
  651. else if (name.equalsIgnoreCase (Constants.DOM_SCHEMA_TYPE)) {
  652. return fConfiguration.getProperty (
  653. Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_LANGUAGE);
  654. }
  655. else if (name.equalsIgnoreCase (Constants.DOM_SCHEMA_LOCATION)) {
  656. return fSchemaLocation;
  657. }
  658. else if (name.equalsIgnoreCase (SYMBOL_TABLE)){
  659. return fConfiguration.getProperty (SYMBOL_TABLE);
  660. }
  661. else if (name.equalsIgnoreCase (DOCUMENT_CLASS_NAME)) {
  662. return fConfiguration.getProperty (DOCUMENT_CLASS_NAME);
  663. }
  664. else {
  665. String msg =
  666. DOMMessageFormatter.formatMessage (
  667. DOMMessageFormatter.DOM_DOMAIN,
  668. "FEATURE_NOT_FOUND",
  669. new Object[] { name });
  670. throw new DOMException (DOMException.NOT_FOUND_ERR, msg);
  671. }
  672. return null;
  673. }
  674. public boolean canSetParameter (String name, Object value) {
  675. if(value instanceof Boolean){
  676. boolean state = ((Boolean)value).booleanValue ();
  677. if ( name.equalsIgnoreCase (Constants.DOM_SUPPORTED_MEDIATYPES_ONLY)
  678. || name.equalsIgnoreCase(Constants.DOM_NORMALIZE_CHARACTERS)
  679. || name.equalsIgnoreCase(Constants.DOM_CHECK_CHAR_NORMALIZATION )
  680. || name.equalsIgnoreCase (Constants.DOM_CANONICAL_FORM) ) {
  681. // true is not supported
  682. return (state) ? false : true;
  683. }
  684. else if (name.equalsIgnoreCase (Constants.DOM_NAMESPACE_DECLARATIONS)
  685. || name.equalsIgnoreCase (Constants.DOM_WELLFORMED)
  686. || name.equalsIgnoreCase (Constants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS)) {
  687. // false is not supported
  688. return (state) ? true : false;
  689. }
  690. else if (name.equalsIgnoreCase (Constants.DOM_CDATA_SECTIONS)
  691. || name.equalsIgnoreCase (Constants.DOM_CHARSET_OVERRIDES_XML_ENCODING)
  692. || name.equalsIgnoreCase (Constants.DOM_COMMENTS)
  693. || name.equalsIgnoreCase (Constants.DOM_DATATYPE_NORMALIZATION)
  694. || name.equalsIgnoreCase (Constants.DOM_DISALLOW_DOCTYPE)
  695. || name.equalsIgnoreCase (Constants.DOM_ENTITIES)
  696. || name.equalsIgnoreCase (Constants.DOM_INFOSET)
  697. || name.equalsIgnoreCase (Constants.DOM_NAMESPACES)
  698. || name.equalsIgnoreCase (Constants.DOM_VALIDATE)
  699. || name.equalsIgnoreCase (Constants.DOM_VALIDATE_IF_SCHEMA)
  700. || name.equalsIgnoreCase (Constants.DOM_ELEMENT_CONTENT_WHITESPACE)
  701. || name.equalsIgnoreCase (Constants.DOM_XMLDECL)) {
  702. return true;
  703. }
  704. // Recognize Xerces features.
  705. try {
  706. fConfiguration.getFeature(name.toLowerCase(Locale.ENGLISH));
  707. return true;
  708. }
  709. catch (XMLConfigurationException e) {
  710. return false;
  711. }
  712. }
  713. else { // check properties
  714. if (name.equalsIgnoreCase (Constants.DOM_ERROR_HANDLER)) {
  715. if (value instanceof DOMErrorHandler || value == null) {
  716. return true;
  717. }
  718. return false;
  719. }
  720. else if (name.equalsIgnoreCase (Constants.DOM_RESOURCE_RESOLVER)) {
  721. if (value instanceof LSResourceResolver || value == null) {
  722. return true;
  723. }
  724. return false;
  725. }
  726. else if (name.equalsIgnoreCase (Constants.DOM_SCHEMA_TYPE)) {
  727. if ((value instanceof String
  728. && (value.equals (Constants.NS_XMLSCHEMA)
  729. || value.equals (Constants.NS_DTD))) || value == null) {
  730. return true;
  731. }
  732. return false;
  733. }
  734. else if (name.equalsIgnoreCase (Constants.DOM_SCHEMA_LOCATION)) {
  735. if (value instanceof String || value == null)
  736. return true;
  737. return false;
  738. }
  739. else if (name.equalsIgnoreCase (DOCUMENT_CLASS_NAME)){
  740. return true;
  741. }
  742. return false;
  743. }
  744. }
  745. /**
  746. * DOM Level 3 CR - Experimental.
  747. *
  748. * The list of the parameters supported by this
  749. * <code>DOMConfiguration</code> object and for which at least one value
  750. * can be set by the application. Note that this list can also contain
  751. * parameter names defined outside this specification.
  752. */
  753. public DOMStringList getParameterNames () {
  754. if (fRecognizedParameters == null){
  755. Vector parameters = new Vector();
  756. // REVISIT: add Xerces recognized properties/features
  757. parameters.add(Constants.DOM_NAMESPACES);
  758. parameters.add(Constants.DOM_CDATA_SECTIONS);
  759. parameters.add(Constants.DOM_CANONICAL_FORM);
  760. parameters.add(Constants.DOM_NAMESPACE_DECLARATIONS);
  761. parameters.add(Constants.DOM_SPLIT_CDATA);
  762. parameters.add(Constants.DOM_ENTITIES);
  763. parameters.add(Constants.DOM_VALIDATE_IF_SCHEMA);
  764. parameters.add(Constants.DOM_VALIDATE);
  765. parameters.add(Constants.DOM_DATATYPE_NORMALIZATION);
  766. parameters.add(Constants.DOM_CHARSET_OVERRIDES_XML_ENCODING);
  767. parameters.add(Constants.DOM_CHECK_CHAR_NORMALIZATION);
  768. parameters.add(Constants.DOM_SUPPORTED_MEDIATYPES_ONLY);
  769. parameters.add(Constants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS);
  770. parameters.add(Constants.DOM_NORMALIZE_CHARACTERS);
  771. parameters.add(Constants.DOM_WELLFORMED);
  772. parameters.add(Constants.DOM_INFOSET);
  773. parameters.add(Constants.DOM_DISALLOW_DOCTYPE);
  774. parameters.add(Constants.DOM_ELEMENT_CONTENT_WHITESPACE);
  775. parameters.add(Constants.DOM_COMMENTS);
  776. parameters.add(Constants.DOM_ERROR_HANDLER);
  777. parameters.add(Constants.DOM_RESOURCE_RESOLVER);
  778. parameters.add(Constants.DOM_SCHEMA_LOCATION);
  779. parameters.add(Constants.DOM_SCHEMA_TYPE);
  780. fRecognizedParameters = new DOMStringListImpl(parameters);
  781. }
  782. return fRecognizedParameters;
  783. }
  784. /**
  785. * Parse an XML document from a location identified by an URI reference.
  786. * If the URI contains a fragment identifier (see section 4.1 in ), the
  787. * behavior is not defined by this specification.
  788. *
  789. */
  790. public Document parseURI (String uri) throws LSException {
  791. //If DOMParser insstance is already busy parsing another document when this
  792. // method is called, then raise INVALID_STATE_ERR according to DOM L3 LS spec
  793. if ( fBusy ) {
  794. String msg = DOMMessageFormatter.formatMessage (
  795. DOMMessageFormatter.DOM_DOMAIN,
  796. "INVALID_STATE_ERR",null);
  797. throw new DOMException ( DOMException.INVALID_STATE_ERR,msg);
  798. }
  799. XMLInputSource source = new XMLInputSource (null, uri, null);
  800. try {
  801. //since we are depending on application to handle
  802. //multithreading issues this should be ok.
  803. if(!fBusy)currentThread = Thread.currentThread();
  804. fBusy = true;
  805. parse (source);
  806. fBusy = false;
  807. if(abortNow && currentThread.isInterrupted())
  808. {
  809. //reset interrupt state
  810. abortNow = false;
  811. currentThread.interrupted();
  812. }
  813. } catch (Exception e){
  814. fBusy = false;
  815. // Consume this exception if the user
  816. // issued an interrupt or an abort.
  817. if(abortNow && currentThread.isInterrupted())
  818. {
  819. //reset interrupt state
  820. currentThread.interrupted();
  821. }
  822. if(abortNow){
  823. abortNow = false;
  824. return null;
  825. }
  826. if (e != abort) {
  827. if (fErrorHandler != null) {
  828. DOMErrorImpl error = new DOMErrorImpl ();
  829. error.fException = e;
  830. error.fMessage = e.getMessage ();
  831. error.fSeverity = DOMError.SEVERITY_FATAL_ERROR;
  832. fErrorHandler.getErrorHandler ().handleError (error);
  833. }
  834. if (DEBUG) {
  835. e.printStackTrace ();
  836. }
  837. throw new LSException(LSException.PARSE_ERR, e.getMessage());
  838. }
  839. }
  840. return getDocument ();
  841. }
  842. /**
  843. * Parse an XML document from a resource identified by an
  844. * <code>LSInput</code>.
  845. *
  846. */
  847. public Document parse (LSInput is) throws LSException {
  848. // need to wrap the LSInput with an XMLInputSource
  849. XMLInputSource xmlInputSource = dom2xmlInputSource (is);
  850. if ( fBusy ) {
  851. String msg = DOMMessageFormatter.formatMessage (
  852. DOMMessageFormatter.DOM_DOMAIN,
  853. "INVALID_STATE_ERR",null);
  854. throw new DOMException ( DOMException.INVALID_STATE_ERR,msg);
  855. }
  856. try {
  857. //since we are depending on application to handle
  858. //multithreading issues this should be ok.
  859. if(!fBusy)currentThread = Thread.currentThread();
  860. fBusy = true;
  861. parse(xmlInputSource);
  862. fBusy = false;
  863. if(abortNow && currentThread.isInterrupted())
  864. {
  865. //reset interrupt state
  866. abortNow = false;
  867. currentThread.interrupted();
  868. }
  869. } catch (Exception e) {
  870. fBusy = false;
  871. // Consume this exception if the user
  872. // issued an interrupt or an abort.
  873. if(abortNow && currentThread.isInterrupted())
  874. {
  875. //reset interrupt state
  876. currentThread.interrupted();
  877. }
  878. if(abortNow){
  879. abortNow = false;
  880. return null;
  881. }
  882. if (e != abort) {
  883. if (fErrorHandler != null) {
  884. DOMErrorImpl error = new DOMErrorImpl ();
  885. error.fException = e;
  886. error.fMessage = e.getMessage ();
  887. error.fSeverity = DOMError.SEVERITY_FATAL_ERROR;
  888. fErrorHandler.getErrorHandler().handleError (error);
  889. }
  890. if (DEBUG) {
  891. e.printStackTrace ();
  892. }
  893. throw new LSException(LSException.PARSE_ERR, e.getMessage());
  894. }
  895. }
  896. return getDocument ();
  897. }
  898. /**
  899. * Parse an XML document or fragment from a resource identified by an
  900. * <code>LSInput</code> and insert the content into an existing
  901. * document at the position epcified with the <code>contextNode</code>
  902. * and <code>action</code> arguments. When parsing the input stream the
  903. * context node is used for resolving unbound namespace prefixes.
  904. *
  905. * @param is The <code>LSInput</code> from which the source
  906. * document is to be read.
  907. * @param cnode The <code>Node</code> that is used as the context for
  908. * the data that is being parsed.
  909. * @param action This parameter describes which action should be taken
  910. * between the new set of node being inserted and the existing
  911. * children of the context node. The set of possible actions is
  912. * defined above.
  913. * @exception DOMException
  914. * HIERARCHY_REQUEST_ERR: Thrown if this action results in an invalid
  915. * hierarchy (i.e. a Document with more than one document element).
  916. */
  917. public Node parseWithContext (LSInput is, Node cnode,
  918. short action) throws DOMException, LSException {
  919. // REVISIT: need to implement.
  920. throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Not supported");
  921. }
  922. /**
  923. * NON-DOM: convert LSInput to XNIInputSource
  924. *
  925. * @param is
  926. * @return
  927. */
  928. XMLInputSource dom2xmlInputSource(LSInput is) {
  929. // need to wrap the LSInput with an XMLInputSource
  930. XMLInputSource xis = null;
  931. // check whether there is a Reader
  932. // according to DOM, we need to treat such reader as "UTF-16".
  933. if (is.getCharacterStream () != null) {
  934. xis = new XMLInputSource (is.getPublicId (), is.getSystemId (),
  935. is.getBaseURI (), is.getCharacterStream (),
  936. "UTF-16");
  937. }
  938. // check whether there is an InputStream
  939. else if (is.getByteStream () != null) {
  940. xis = new XMLInputSource (is.getPublicId (), is.getSystemId (),
  941. is.getBaseURI (), is.getByteStream (),
  942. is.getEncoding ());
  943. }
  944. // if there is a string data, use a StringReader
  945. // according to DOM, we need to treat such data as "UTF-16".
  946. else if (is.getStringData () != null && is.getStringData().length() > 0) {
  947. xis = new XMLInputSource (is.getPublicId (), is.getSystemId (),
  948. is.getBaseURI (), new StringReader (is.getStringData ()),
  949. "UTF-16");
  950. }
  951. // otherwise, just use the public/system/base Ids
  952. else if ((is.getSystemId() != null && is.getSystemId().length() > 0) ||
  953. (is.getPublicId() != null && is.getPublicId().length() > 0)) {
  954. xis = new XMLInputSource (is.getPublicId (), is.getSystemId (),
  955. is.getBaseURI ());
  956. }
  957. else {
  958. // all inputs are null
  959. if (fErrorHandler != null) {
  960. DOMErrorImpl error = new DOMErrorImpl();
  961. error.fType = "no-input-specified";
  962. error.fMessage = "no-input-specified";
  963. error.fSeverity = DOMError.SEVERITY_FATAL_ERROR;
  964. fErrorHandler.getErrorHandler().handleError(error);
  965. }
  966. throw new LSException(LSException.PARSE_ERR, "no-input-specified");
  967. }
  968. return xis;
  969. }
  970. /**
  971. * @see org.w3c.dom.ls.LSParser#getAsync()
  972. */
  973. public boolean getAsync () {
  974. return false;
  975. }
  976. /**
  977. * @see org.w3c.dom.ls.LSParser#getBusy()
  978. */
  979. public boolean getBusy () {
  980. return fBusy;
  981. }
  982. /**
  983. * @see org.w3c.dom.ls.DOMParser#abort()
  984. */
  985. public void abort () {
  986. // If parse operation is in progress then reset it
  987. if ( fBusy ) {
  988. fBusy = false;
  989. abortNow = true;
  990. try{
  991. //Revisit : Should we also close all opened readers ?
  992. //Work towards other classes supporting abort instead of
  993. //calling reset.
  994. reset();
  995. //interrupt the thread doing the parse operation.
  996. //come out of all block operations.
  997. // current thread could be blocked on read operation.
  998. if(currentThread != null )currentThread.interrupt();
  999. }catch(Exception ex){
  1000. }
  1001. }
  1002. return; // If not busy then this is noop
  1003. }
  1004. } // class DOMParserImpl