1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 2001-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) 2003, 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.xinclude;
  58. import java.io.CharConversionException;
  59. import java.io.IOException;
  60. import java.io.InputStream;
  61. import java.io.Reader;
  62. import java.net.HttpURLConnection;
  63. import java.net.URL;
  64. import java.net.URLConnection;
  65. import java.util.Enumeration;
  66. import java.util.Stack;
  67. import java.util.StringTokenizer;
  68. import java.util.Vector;
  69. import com.sun.org.apache.xerces.internal.impl.Constants;
  70. import com.sun.org.apache.xerces.internal.impl.XMLEntityManager;
  71. import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter;
  72. import com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException;
  73. import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
  74. import com.sun.org.apache.xerces.internal.util.AugmentationsImpl;
  75. import com.sun.org.apache.xerces.internal.util.IntStack;
  76. import com.sun.org.apache.xerces.internal.util.ParserConfigurationSettings;
  77. import com.sun.org.apache.xerces.internal.util.SecurityManager;
  78. import com.sun.org.apache.xerces.internal.util.URI;
  79. import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl;
  80. import com.sun.org.apache.xerces.internal.util.XMLResourceIdentifierImpl;
  81. import com.sun.org.apache.xerces.internal.util.XMLSymbols;
  82. import com.sun.org.apache.xerces.internal.util.URI.MalformedURIException;
  83. import com.sun.org.apache.xerces.internal.xni.Augmentations;
  84. import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
  85. import com.sun.org.apache.xerces.internal.xni.QName;
  86. import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
  87. import com.sun.org.apache.xerces.internal.xni.XMLDTDHandler;
  88. import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler;
  89. import com.sun.org.apache.xerces.internal.xni.XMLLocator;
  90. import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
  91. import com.sun.org.apache.xerces.internal.xni.XMLString;
  92. import com.sun.org.apache.xerces.internal.xni.XNIException;
  93. import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent;
  94. import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
  95. import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
  96. import com.sun.org.apache.xerces.internal.xni.parser.XMLDTDFilter;
  97. import com.sun.org.apache.xerces.internal.xni.parser.XMLDTDSource;
  98. import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentFilter;
  99. import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource;
  100. import com.sun.org.apache.xerces.internal.xni.parser.XMLEntityResolver;
  101. import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
  102. import com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration;
  103. /**
  104. * <p>
  105. * This is a pipeline component which performs XInclude handling, according to the
  106. * W3C specification for XML Inclusions.
  107. * </p>
  108. * <p>
  109. * This component analyzes each event in the pipeline, looking for <include>
  110. * elements. An <include> element is one which has a namespace of
  111. * <code>http://www.w3.org/2001/XInclude</code> and a localname of <code>include</code>.
  112. * When it finds an <include> element, it attempts to include the file specified
  113. * in the <code>href</code> attribute of the element. If inclusion succeeds, all
  114. * children of the <include> element are ignored (with the exception of
  115. * checking for invalid children as outlined in the specification). If the inclusion
  116. * fails, the <fallback> child of the <include> element is processed.
  117. * </p>
  118. * <p>
  119. * See the <a href="http://www.w3.org/TR/xinclude/">XInclude specification</a> for
  120. * more information on how XInclude is to be used.
  121. * </p>
  122. * <p>
  123. * This component requires the following features and properties from the
  124. * component manager that uses it:
  125. * <ul>
  126. * <li>http://xml.org/sax/features/allow-dtd-events-after-endDTD</li>
  127. * <li>http://apache.org/xml/properties/internal/error-reporter</li>
  128. * <li>http://apache.org/xml/properties/internal/entity-resolver</li>
  129. * </ul>
  130. * Furthermore, the <code>NamespaceContext</code> used in the pipeline is required
  131. * to be an instance of <code>XIncludeNamespaceSupport</code>.
  132. * </p>
  133. * <p>
  134. * Currently, this implementation has only partial support for the XInclude specification.
  135. * Specifically, it is missing support for XPointer document fragments. Thus, only whole
  136. * documents can be included using this component in the pipeline.
  137. * </p>
  138. *
  139. * @author Peter McCracken, IBM
  140. *
  141. * @version $Id: XIncludeHandler.java,v 1.26 2004/04/15 04:51:56 mrglavas Exp $
  142. *
  143. * @see XIncludeNamespaceSupport
  144. */
  145. public class XIncludeHandler
  146. implements XMLComponent, XMLDocumentFilter, XMLDTDFilter {
  147. //Xpointer support
  148. //START
  149. public final static String XPOINTER_DEFAULT_CONFIGURATION =
  150. "com.sun.org.apache.xerces.internal.parsers.XPointerParserConfiguration";
  151. protected static final String XPOINTER_SCHEMA =
  152. Constants.XERCES_PROPERTY_PREFIX + Constants.XPOINTER_SCHEMA_PROPERTY;
  153. protected static final String XINCLUDE_AWARE =
  154. Constants.XERCES_FEATURE_PREFIX + Constants.XINCLUDE_AWARE ;
  155. //END
  156. public final static String XINCLUDE_DEFAULT_CONFIGURATION =
  157. "com.sun.org.apache.xerces.internal.parsers.XIncludeParserConfiguration";
  158. public final static String HTTP_ACCEPT = "Accept";
  159. public final static String HTTP_ACCEPT_LANGUAGE = "Accept-Language";
  160. public final static String HTTP_ACCEPT_CHARSET = "Accept-Charset";
  161. public final static String XPOINTER = "xpointer";
  162. public final static String XINCLUDE_NS_URI =
  163. "http://www.w3.org/2001/XInclude".intern();
  164. public final static String XINCLUDE_INCLUDE = "include".intern();
  165. public final static String XINCLUDE_FALLBACK = "fallback".intern();
  166. public final static String XINCLUDE_PARSE_XML = "xml".intern();
  167. public final static String XINCLUDE_PARSE_TEXT = "text".intern();
  168. public final static String XINCLUDE_ATTR_HREF = "href".intern();
  169. public final static String XINCLUDE_ATTR_PARSE = "parse".intern();
  170. public final static String XINCLUDE_ATTR_ENCODING = "encoding".intern();
  171. public final static String XINCLUDE_ATTR_ACCEPT = "accept".intern();
  172. public final static String XINCLUDE_ATTR_ACCEPT_LANGUAGE = "accept-language".intern();
  173. public final static String XINCLUDE_ATTR_ACCEPT_CHARSET = "accept-charset".intern();
  174. // Top Level Information Items have [included] property in infoset
  175. public final static String XINCLUDE_INCLUDED = "[included]".intern();
  176. /** The identifier for the Augmentation that contains the current base URI */
  177. public final static String CURRENT_BASE_URI = "currentBaseURI";
  178. // used for adding [base URI] attributes
  179. public final static String XINCLUDE_BASE = "base";
  180. public final static QName XML_BASE_QNAME =
  181. new QName(
  182. XMLSymbols.PREFIX_XML,
  183. XINCLUDE_BASE,
  184. XMLSymbols.PREFIX_XML + ":" + XINCLUDE_BASE,
  185. NamespaceContext.XML_URI);
  186. public final static QName NEW_NS_ATTR_QNAME =
  187. new QName(
  188. XMLSymbols.PREFIX_XMLNS,
  189. "",
  190. XMLSymbols.PREFIX_XMLNS + ":",
  191. NamespaceContext.XMLNS_URI);
  192. // Processing States
  193. private final static int STATE_NORMAL_PROCESSING = 1;
  194. // we go into this state after a successful include (thus we ignore the children
  195. // of the include) or after a fallback
  196. private final static int STATE_IGNORE = 2;
  197. // we go into this state after a failed include. If we don't encounter a fallback
  198. // before we reach the end include tag, it's a fatal error
  199. private final static int STATE_EXPECT_FALLBACK = 3;
  200. // recognized features and properties
  201. /** Feature identifier: allow notation and unparsed entity events to be sent out of order. */
  202. protected static final String ALLOW_UE_AND_NOTATION_EVENTS =
  203. Constants.SAX_FEATURE_PREFIX
  204. + Constants.ALLOW_DTD_EVENTS_AFTER_ENDDTD_FEATURE;
  205. /** Property identifier: error reporter. */
  206. protected static final String ERROR_REPORTER =
  207. Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
  208. /** Property identifier: entity resolver. */
  209. protected static final String ENTITY_RESOLVER =
  210. Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY;
  211. /** property identifier: security manager. */
  212. protected static final String SECURITY_MANAGER =
  213. Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY;
  214. /** Recognized features. */
  215. private static final String[] RECOGNIZED_FEATURES =
  216. { ALLOW_UE_AND_NOTATION_EVENTS };
  217. /** Feature defaults. */
  218. private static final Boolean[] FEATURE_DEFAULTS = { Boolean.TRUE };
  219. /** Recognized properties. */
  220. private static final String[] RECOGNIZED_PROPERTIES =
  221. { ERROR_REPORTER, ENTITY_RESOLVER, XPOINTER_SCHEMA };
  222. /** Property defaults. */
  223. private static final Object[] PROPERTY_DEFAULTS = { null, null, null };
  224. // instance variables
  225. // for XMLDocumentFilter
  226. protected XMLDocumentHandler fDocumentHandler;
  227. protected XMLDocumentSource fDocumentSource;
  228. protected XPointerFramework fXPointerFramework = null;
  229. protected XPointerSchema [] fXPointerSchema;
  230. // for XMLDTDFilter
  231. protected XMLDTDHandler fDTDHandler;
  232. protected XMLDTDSource fDTDSource;
  233. // for XIncludeHandler
  234. protected XIncludeHandler fParentXIncludeHandler;
  235. // It's "feels wrong" to store this value here. However,
  236. // calculating it can be time consuming, so we cache it.
  237. // It's never going to change in the lifetime of this XIncludeHandler
  238. protected String fParentRelativeURI;
  239. // we cache the child parser configuration, so we don't have to re-create
  240. // the objects when the parser is re-used
  241. protected XMLParserConfiguration fChildConfig;
  242. protected XMLLocator fDocLocation;
  243. protected XIncludeNamespaceSupport fNamespaceContext;
  244. protected XMLErrorReporter fErrorReporter;
  245. protected XMLEntityResolver fEntityResolver;
  246. protected SecurityManager fSecurityManager;
  247. // these are needed for XML Base processing
  248. protected XMLResourceIdentifier fCurrentBaseURI;
  249. protected IntStack baseURIScope;
  250. protected Stack baseURI;
  251. protected Stack literalSystemID;
  252. protected Stack expandedSystemID;
  253. // used for passing features on to child XIncludeHandler objects
  254. protected ParserConfigurationSettings fSettings;
  255. // The current element depth. We start at depth 0 (before we've reached any elements)
  256. // The first element is at depth 1.
  257. private int fDepth;
  258. // this value must be at least 1
  259. private static final int INITIAL_SIZE = 8;
  260. // Used to ensure that fallbacks are always children of include elements,
  261. // and that include elements are never children of other include elements.
  262. // An index contains true if the ancestor of the current element which resides
  263. // at that depth was an include element.
  264. private boolean[] fSawInclude = new boolean[INITIAL_SIZE];
  265. // Ensures that only one fallback element can be at a single depth.
  266. // An index contains true if we have seen any fallback elements at that depth,
  267. // and it is only reset to false when the end tag of the parent is encountered.
  268. private boolean[] fSawFallback = new boolean[INITIAL_SIZE];
  269. // The state of the processor at each given depth.
  270. private int[] fState = new int[INITIAL_SIZE];
  271. // buffering the necessary DTD events
  272. private Vector fNotations;
  273. private Vector fUnparsedEntities;
  274. // for SAX compatibility.
  275. // Has the value of the ALLOW_UE_AND_NOTATION_EVENTS feature
  276. private boolean fSendUEAndNotationEvents;
  277. // track the version of the document being parsed
  278. private boolean fIsXML11;
  279. // track whether a DTD is being parsed
  280. private boolean fInDTD;
  281. // Constructors
  282. public XIncludeHandler() {
  283. fDepth = 0;
  284. fSawFallback[fDepth] = false;
  285. fSawInclude[fDepth] = false;
  286. fState[fDepth] = STATE_NORMAL_PROCESSING;
  287. fNotations = new Vector();
  288. fUnparsedEntities = new Vector();
  289. baseURIScope = new IntStack();
  290. baseURI = new Stack();
  291. literalSystemID = new Stack();
  292. expandedSystemID = new Stack();
  293. fCurrentBaseURI = new XMLResourceIdentifierImpl();
  294. }
  295. // XMLComponent methods
  296. public void reset(XMLComponentManager componentManager)
  297. throws XNIException {
  298. fNamespaceContext = null;
  299. fDepth = 0;
  300. fNotations = new Vector();
  301. fUnparsedEntities = new Vector();
  302. fParentRelativeURI = null;
  303. fIsXML11 = false;
  304. fInDTD = false;
  305. baseURIScope.clear();
  306. baseURI.clear();
  307. literalSystemID.clear();
  308. expandedSystemID.clear();
  309. // REVISIT: Find a better method for maintaining
  310. // the state of the XInclude processor. These arrays
  311. // can potentially grow quite large. Cleaning them
  312. // out on reset may be very time consuming. -- mrglavas
  313. //
  314. // clear the previous settings from the arrays
  315. for (int i = 0; i < fState.length; ++i) {
  316. fState[i] = STATE_NORMAL_PROCESSING;
  317. }
  318. for (int i = 0; i < fSawFallback.length; ++i) {
  319. fSawFallback[i] = false;
  320. }
  321. for (int i = 0; i < fSawInclude.length; ++i) {
  322. fSawInclude[i] = false;
  323. }
  324. try {
  325. fSendUEAndNotationEvents =
  326. componentManager.getFeature(ALLOW_UE_AND_NOTATION_EVENTS);
  327. if (fChildConfig != null) {
  328. fChildConfig.setFeature(
  329. ALLOW_UE_AND_NOTATION_EVENTS,
  330. fSendUEAndNotationEvents);
  331. }
  332. }
  333. catch (XMLConfigurationException e) {
  334. }
  335. // Get error reporter.
  336. try {
  337. XMLErrorReporter value =
  338. (XMLErrorReporter)componentManager.getProperty(ERROR_REPORTER);
  339. if (value != null) {
  340. setErrorReporter(value);
  341. if (fChildConfig != null) {
  342. fChildConfig.setProperty(ERROR_REPORTER, value);
  343. }
  344. }
  345. }
  346. catch (XMLConfigurationException e) {
  347. fErrorReporter = null;
  348. }
  349. // Get entity resolver.
  350. try {
  351. XMLEntityResolver value =
  352. (XMLEntityResolver)componentManager.getProperty(
  353. ENTITY_RESOLVER);
  354. if (value != null) {
  355. fEntityResolver = value;
  356. if (fChildConfig != null) {
  357. fChildConfig.setProperty(ENTITY_RESOLVER, value);
  358. }
  359. }
  360. }
  361. catch (XMLConfigurationException e) {
  362. fEntityResolver = null;
  363. }
  364. try {
  365. fXPointerSchema =
  366. (XPointerSchema [])componentManager.getProperty(
  367. XPOINTER_SCHEMA);
  368. }
  369. catch (XMLConfigurationException e) {
  370. fXPointerSchema = null;
  371. }
  372. // Get security manager.
  373. try {
  374. SecurityManager value =
  375. (SecurityManager)componentManager.getProperty(
  376. SECURITY_MANAGER);
  377. if (value != null) {
  378. fSecurityManager = value;
  379. if (fChildConfig != null) {
  380. fChildConfig.setProperty(SECURITY_MANAGER, value);
  381. }
  382. }
  383. }
  384. catch (XMLConfigurationException e) {
  385. fSecurityManager = null;
  386. }
  387. fSettings = new ParserConfigurationSettings();
  388. copyFeatures(componentManager, fSettings);
  389. // Don't reset fChildConfig -- we don't want it to share the same components.
  390. // It will be reset when it is actually used to parse something.
  391. } // reset(XMLComponentManager)
  392. /**
  393. * Returns a list of feature identifiers that are recognized by
  394. * this component. This method may return null if no features
  395. * are recognized by this component.
  396. */
  397. public String[] getRecognizedFeatures() {
  398. return RECOGNIZED_FEATURES;
  399. } // getRecognizedFeatures():String[]
  400. /**
  401. * Sets the state of a feature. This method is called by the component
  402. * manager any time after reset when a feature changes state.
  403. * <p>
  404. * <strong>Note:</strong> Components should silently ignore features
  405. * that do not affect the operation of the component.
  406. *
  407. * @param featureId The feature identifier.
  408. * @param state The state of the feature.
  409. *
  410. * @throws SAXNotRecognizedException The component should not throw
  411. * this exception.
  412. * @throws SAXNotSupportedException The component should not throw
  413. * this exception.
  414. */
  415. public void setFeature(String featureId, boolean state)
  416. throws XMLConfigurationException {
  417. if (featureId.equals(ALLOW_UE_AND_NOTATION_EVENTS)) {
  418. fSendUEAndNotationEvents = state;
  419. }
  420. if (fSettings != null) {
  421. fSettings.setFeature(featureId, state);
  422. }
  423. } // setFeature(String,boolean)
  424. /**
  425. * Returns a list of property identifiers that are recognized by
  426. * this component. This method may return null if no properties
  427. * are recognized by this component.
  428. */
  429. public String[] getRecognizedProperties() {
  430. return RECOGNIZED_PROPERTIES;
  431. } // getRecognizedProperties():String[]
  432. /**
  433. * Sets the value of a property. This method is called by the component
  434. * manager any time after reset when a property changes value.
  435. * <p>
  436. * <strong>Note:</strong> Components should silently ignore properties
  437. * that do not affect the operation of the component.
  438. *
  439. * @param propertyId The property identifier.
  440. * @param value The value of the property.
  441. *
  442. * @throws SAXNotRecognizedException The component should not throw
  443. * this exception.
  444. * @throws SAXNotSupportedException The component should not throw
  445. * this exception.
  446. */
  447. public void setProperty(String propertyId, Object value)
  448. throws XMLConfigurationException {
  449. if (propertyId.equals(ERROR_REPORTER)) {
  450. setErrorReporter((XMLErrorReporter)value);
  451. if (fChildConfig != null) {
  452. fChildConfig.setProperty(propertyId, value);
  453. }
  454. }
  455. if (propertyId.equals(ENTITY_RESOLVER)) {
  456. fEntityResolver = (XMLEntityResolver)value;
  457. if (fChildConfig != null) {
  458. fChildConfig.setProperty(propertyId, value);
  459. }
  460. }
  461. if (propertyId.equals(SECURITY_MANAGER)) {
  462. fSecurityManager = (SecurityManager)value;
  463. if (fChildConfig != null) {
  464. fChildConfig.setProperty(propertyId, value);
  465. }
  466. }
  467. } // setProperty(String,Object)
  468. /**
  469. * Returns the default state for a feature, or null if this
  470. * component does not want to report a default value for this
  471. * feature.
  472. *
  473. * @param featureId The feature identifier.
  474. *
  475. * @since Xerces 2.2.0
  476. */
  477. public Boolean getFeatureDefault(String featureId) {
  478. for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) {
  479. if (RECOGNIZED_FEATURES[i].equals(featureId)) {
  480. return FEATURE_DEFAULTS[i];
  481. }
  482. }
  483. return null;
  484. } // getFeatureDefault(String):Boolean
  485. /**
  486. * Returns the default state for a property, or null if this
  487. * component does not want to report a default value for this
  488. * property.
  489. *
  490. * @param propertyId The property identifier.
  491. *
  492. * @since Xerces 2.2.0
  493. */
  494. public Object getPropertyDefault(String propertyId) {
  495. for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) {
  496. if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) {
  497. return PROPERTY_DEFAULTS[i];
  498. }
  499. }
  500. return null;
  501. } // getPropertyDefault(String):Object
  502. public void setDocumentHandler(XMLDocumentHandler handler) {
  503. fDocumentHandler = handler;
  504. }
  505. public XMLDocumentHandler getDocumentHandler() {
  506. return fDocumentHandler;
  507. }
  508. // XMLDocumentHandler methods
  509. /**
  510. * Event sent at the start of the document.
  511. *
  512. * A fatal error will occur here, if it is detected that this document has been processed
  513. * before.
  514. *
  515. * This event is only passed on to the document handler if this is the root document.
  516. */
  517. public void startDocument(
  518. XMLLocator locator,
  519. String encoding,
  520. NamespaceContext namespaceContext,
  521. Augmentations augs)
  522. throws XNIException {
  523. // we do this to ensure that the proper location is reported in errors
  524. // otherwise, the locator from the root document would always be used
  525. if(fErrorReporter != null)
  526. fErrorReporter.setDocumentLocator(locator);
  527. if (!isRootDocument()
  528. && fParentXIncludeHandler.searchForRecursiveIncludes(locator)) {
  529. reportFatalError(
  530. "RecursiveInclude",
  531. new Object[] { locator.getExpandedSystemId()});
  532. }
  533. if (!(namespaceContext instanceof XIncludeNamespaceSupport)) {
  534. reportFatalError("IncompatibleNamespaceContext");
  535. }
  536. fNamespaceContext = (XIncludeNamespaceSupport)namespaceContext;
  537. fDocLocation = locator;
  538. // initialize the current base URI
  539. fCurrentBaseURI.setBaseSystemId(locator.getBaseSystemId());
  540. fCurrentBaseURI.setExpandedSystemId(locator.getExpandedSystemId());
  541. fCurrentBaseURI.setLiteralSystemId(locator.getLiteralSystemId());
  542. saveBaseURI();
  543. if (augs == null) {
  544. augs = new AugmentationsImpl();
  545. }
  546. augs.putItem(CURRENT_BASE_URI, fCurrentBaseURI);
  547. if (isRootDocument() && fDocumentHandler != null) {
  548. fDocumentHandler.startDocument(
  549. locator,
  550. encoding,
  551. namespaceContext,
  552. augs);
  553. }
  554. }
  555. public void xmlDecl(
  556. String version,
  557. String encoding,
  558. String standalone,
  559. Augmentations augs)
  560. throws XNIException {
  561. fIsXML11 = "1.1".equals(version);
  562. if (isRootDocument() && fDocumentHandler != null) {
  563. fDocumentHandler.xmlDecl(version, encoding, standalone, augs);
  564. }
  565. }
  566. public void doctypeDecl(
  567. String rootElement,
  568. String publicId,
  569. String systemId,
  570. Augmentations augs)
  571. throws XNIException {
  572. if (isRootDocument() && fDocumentHandler != null) {
  573. fDocumentHandler.doctypeDecl(rootElement, publicId, systemId, augs);
  574. }
  575. }
  576. public void comment(XMLString text, Augmentations augs)
  577. throws XNIException {
  578. if (!fInDTD) {
  579. if (fDocumentHandler != null
  580. && getState() == STATE_NORMAL_PROCESSING) {
  581. fDepth++;
  582. augs = modifyAugmentations(augs);
  583. fDocumentHandler.comment(text, augs);
  584. fDepth--;
  585. }
  586. }
  587. else if (fDTDHandler != null) {
  588. fDTDHandler.comment(text, augs);
  589. }
  590. }
  591. public void processingInstruction(
  592. String target,
  593. XMLString data,
  594. Augmentations augs)
  595. throws XNIException {
  596. if (!fInDTD) {
  597. if (fDocumentHandler != null
  598. && getState() == STATE_NORMAL_PROCESSING) {
  599. // we need to change the depth like this so that modifyAugmentations() works
  600. fDepth++;
  601. augs = modifyAugmentations(augs);
  602. fDocumentHandler.processingInstruction(target, data, augs);
  603. fDepth--;
  604. }
  605. }
  606. else if (fDTDHandler != null) {
  607. fDTDHandler.processingInstruction(target, data, augs);
  608. }
  609. }
  610. public void startElement(
  611. QName element,
  612. XMLAttributes attributes,
  613. Augmentations augs)
  614. throws XNIException {
  615. fDepth++;
  616. setState(getState(fDepth - 1));
  617. // we process the xml:base attributes regardless of what type of element it is
  618. processXMLBaseAttributes(attributes);
  619. if (isIncludeElement(element)) {
  620. boolean success = this.handleIncludeElement(attributes);
  621. if (success) {
  622. setState(STATE_IGNORE);
  623. }
  624. else {
  625. setState(STATE_EXPECT_FALLBACK);
  626. }
  627. }
  628. else if (isFallbackElement(element)) {
  629. this.handleFallbackElement();
  630. }
  631. else if (
  632. fDocumentHandler != null
  633. && getState() == STATE_NORMAL_PROCESSING) {
  634. augs = modifyAugmentations(augs);
  635. attributes = processAttributes(attributes);
  636. fDocumentHandler.startElement(element, attributes, augs);
  637. }
  638. }
  639. public void emptyElement(
  640. QName element,
  641. XMLAttributes attributes,
  642. Augmentations augs)
  643. throws XNIException {
  644. fDepth++;
  645. setState(getState(fDepth - 1));
  646. // we process the xml:base attributes regardless of what type of element it is
  647. processXMLBaseAttributes(attributes);
  648. if (isIncludeElement(element)) {
  649. boolean success = this.handleIncludeElement(attributes);
  650. if (success) {
  651. setState(STATE_IGNORE);
  652. }
  653. else {
  654. reportFatalError("NoFallback");
  655. }
  656. }
  657. else if (isFallbackElement(element)) {
  658. this.handleFallbackElement();
  659. }
  660. else if (hasXIncludeNamespace(element)) {
  661. if (getSawInclude(fDepth - 1)) {
  662. reportFatalError(
  663. "IncludeChild",
  664. new Object[] { element.rawname });
  665. }
  666. }
  667. else if (
  668. fDocumentHandler != null
  669. && getState() == STATE_NORMAL_PROCESSING) {
  670. augs = modifyAugmentations(augs);
  671. attributes = processAttributes(attributes);
  672. fDocumentHandler.emptyElement(element, attributes, augs);
  673. }
  674. // reset the out of scope stack elements
  675. setSawFallback(fDepth + 1, false);
  676. setSawInclude(fDepth + 1, false);
  677. // check if an xml:base has gone out of scope
  678. if (baseURIScope.size() > 0 && fDepth == baseURIScope.peek()) {
  679. // pop the values from the stack
  680. restoreBaseURI();
  681. }
  682. fDepth--;
  683. }
  684. public void endElement(QName element, Augmentations augs)
  685. throws XNIException {
  686. if (isIncludeElement(element)) {
  687. // if we're ending an include element, and we were expecting a fallback
  688. // we check to see if the children of this include element contained a fallback
  689. if (getState() == STATE_EXPECT_FALLBACK
  690. && !getSawFallback(fDepth + 1)) {
  691. reportFatalError("NoFallback");
  692. }
  693. }
  694. if (isFallbackElement(element)) {
  695. // the state would have been set to normal processing if we were expecting the fallback element
  696. // now that we're done processing it, we should ignore all the other children of the include element
  697. if (getState() == STATE_NORMAL_PROCESSING) {
  698. setState(STATE_IGNORE);
  699. }
  700. }
  701. else if (
  702. fDocumentHandler != null
  703. && getState() == STATE_NORMAL_PROCESSING) {
  704. fDocumentHandler.endElement(element, augs);
  705. }
  706. // reset the out of scope stack elements
  707. setSawFallback(fDepth + 1, false);
  708. setSawInclude(fDepth + 1, false);
  709. // check if an xml:base has gone out of scope
  710. if (baseURIScope.size() > 0 && fDepth == baseURIScope.peek()) {
  711. // pop the values from the stack
  712. restoreBaseURI();
  713. }
  714. fDepth--;
  715. }
  716. public void startGeneralEntity(
  717. String name,
  718. XMLResourceIdentifier resId,
  719. String encoding,
  720. Augmentations augs)
  721. throws XNIException {
  722. if (fDocumentHandler != null
  723. && getState() == STATE_NORMAL_PROCESSING) {
  724. fDocumentHandler.startGeneralEntity(name, resId, encoding, augs);
  725. }
  726. }
  727. public void textDecl(String version, String encoding, Augmentations augs)
  728. throws XNIException {
  729. if (fDocumentHandler != null
  730. && getState() == STATE_NORMAL_PROCESSING) {
  731. fDocumentHandler.textDecl(version, encoding, augs);
  732. }
  733. }
  734. public void endGeneralEntity(String name, Augmentations augs)
  735. throws XNIException {
  736. if (fDocumentHandler != null
  737. && getState() == STATE_NORMAL_PROCESSING) {
  738. fDocumentHandler.endGeneralEntity(name, augs);
  739. }
  740. }
  741. public void characters(XMLString text, Augmentations augs)
  742. throws XNIException {
  743. if (fDocumentHandler != null
  744. && getState() == STATE_NORMAL_PROCESSING) {
  745. // we need to change the depth like this so that modifyAugmentations() works
  746. fDepth++;
  747. augs = modifyAugmentations(augs);
  748. fDocumentHandler.characters(text, augs);
  749. fDepth--;
  750. }
  751. }
  752. public void ignorableWhitespace(XMLString text, Augmentations augs)
  753. throws XNIException {
  754. if (fDocumentHandler != null
  755. && getState() == STATE_NORMAL_PROCESSING) {
  756. fDocumentHandler.ignorableWhitespace(text, augs);
  757. }
  758. }
  759. public void startCDATA(Augmentations augs) throws XNIException {
  760. if (fDocumentHandler != null
  761. && getState() == STATE_NORMAL_PROCESSING) {
  762. fDocumentHandler.startCDATA(augs);
  763. }
  764. }
  765. public void endCDATA(Augmentations augs) throws XNIException {
  766. if (fDocumentHandler != null
  767. && getState() == STATE_NORMAL_PROCESSING) {
  768. fDocumentHandler.endCDATA(augs);
  769. }
  770. }
  771. public void endDocument(Augmentations augs) throws XNIException {
  772. if (isRootDocument() && fDocumentHandler != null) {
  773. fDocumentHandler.endDocument(augs);
  774. }
  775. }
  776. public void setDocumentSource(XMLDocumentSource source) {
  777. fDocumentSource = source;
  778. }
  779. public XMLDocumentSource getDocumentSource() {
  780. return fDocumentSource;
  781. }
  782. // DTDHandler methods
  783. // We are only interested in the notation and unparsed entity declarations,
  784. // the rest we just pass on
  785. /* (non-Javadoc)
  786. * @see com.sun.org.apache.xerces.internal.xni.XMLDTDHandler#attributeDecl(java.lang.String, java.lang.String, java.lang.String, java.lang.String[], java.lang.String, com.sun.org.apache.xerces.internal.xni.XMLString, com.sun.org.apache.xerces.internal.xni.XMLString, com.sun.org.apache.xerces.internal.xni.Augmentations)
  787. */
  788. public void attributeDecl(
  789. String elementName,
  790. String attributeName,
  791. String type,
  792. String[] enumeration,
  793. String defaultType,
  794. XMLString defaultValue,
  795. XMLString nonNormalizedDefaultValue,
  796. Augmentations augmentations)
  797. throws XNIException {
  798. if (fDTDHandler != null) {
  799. fDTDHandler.attributeDecl(
  800. elementName,
  801. attributeName,
  802. type,
  803. enumeration,
  804. defaultType,
  805. defaultValue,
  806. nonNormalizedDefaultValue,
  807. augmentations);
  808. }
  809. }
  810. /* (non-Javadoc)
  811. * @see com.sun.org.apache.xerces.internal.xni.XMLDTDHandler#elementDecl(java.lang.String, java.lang.String, com.sun.org.apache.xerces.internal.xni.Augmentations)
  812. */
  813. public void elementDecl(
  814. String name,
  815. String contentModel,
  816. Augmentations augmentations)
  817. throws XNIException {
  818. if (fDTDHandler != null) {
  819. fDTDHandler.elementDecl(name, contentModel, augmentations);
  820. }
  821. }
  822. /* (non-Javadoc)
  823. * @see com.sun.org.apache.xerces.internal.xni.XMLDTDHandler#endAttlist(com.sun.org.apache.xerces.internal.xni.Augmentations)
  824. */
  825. public void endAttlist(Augmentations augmentations) throws XNIException {
  826. if (fDTDHandler != null) {
  827. fDTDHandler.endAttlist(augmentations);
  828. }
  829. }
  830. /* (non-Javadoc)
  831. * @see com.sun.org.apache.xerces.internal.xni.XMLDTDHandler#endConditional(com.sun.org.apache.xerces.internal.xni.Augmentations)
  832. */
  833. public void endConditional(Augmentations augmentations)
  834. throws XNIException {
  835. if (fDTDHandler != null) {
  836. fDTDHandler.endConditional(augmentations);
  837. }
  838. }
  839. /* (non-Javadoc)
  840. * @see com.sun.org.apache.xerces.internal.xni.XMLDTDHandler#endDTD(com.sun.org.apache.xerces.internal.xni.Augmentations)
  841. */
  842. public void endDTD(Augmentations augmentations) throws XNIException {
  843. if (fDTDHandler != null) {
  844. fDTDHandler.endDTD(augmentations);
  845. }
  846. fInDTD = false;
  847. }
  848. /* (non-Javadoc)
  849. * @see com.sun.org.apache.xerces.internal.xni.XMLDTDHandler#endExternalSubset(com.sun.org.apache.xerces.internal.xni.Augmentations)
  850. */
  851. public void endExternalSubset(Augmentations augmentations)
  852. throws XNIException {
  853. if (fDTDHandler != null) {
  854. fDTDHandler.endExternalSubset(augmentations);
  855. }
  856. }
  857. /* (non-Javadoc)
  858. * @see com.sun.org.apache.xerces.internal.xni.XMLDTDHandler#endParameterEntity(java.lang.String, com.sun.org.apache.xerces.internal.xni.Augmentations)
  859. */
  860. public void endParameterEntity(String name, Augmentations augmentations)
  861. throws XNIException {
  862. if (fDTDHandler != null) {
  863. fDTDHandler.endParameterEntity(name, augmentations);
  864. }
  865. }
  866. /* (non-Javadoc)
  867. * @see com.sun.org.apache.xerces.internal.xni.XMLDTDHandler#externalEntityDecl(java.lang.String, com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier, com.sun.org.apache.xerces.internal.xni.Augmentations)
  868. */
  869. public void externalEntityDecl(
  870. String name,
  871. XMLResourceIdentifier identifier,
  872. Augmentations augmentations)
  873. throws XNIException {
  874. if (fDTDHandler != null) {
  875. fDTDHandler.externalEntityDecl(name, identifier, augmentations);
  876. }
  877. }
  878. /* (non-Javadoc)
  879. * @see com.sun.org.apache.xerces.internal.xni.XMLDTDHandler#getDTDSource()
  880. */
  881. public XMLDTDSource getDTDSource() {
  882. return fDTDSource;
  883. }
  884. /* (non-Javadoc)
  885. * @see com.sun.org.apache.xerces.internal.xni.XMLDTDHandler#ignoredCharacters(com.sun.org.apache.xerces.internal.xni.XMLString, com.sun.org.apache.xerces.internal.xni.Augmentations)
  886. */
  887. public void ignoredCharacters(XMLString text, Augmentations augmentations)
  888. throws XNIException {
  889. if (fDTDHandler != null) {
  890. fDTDHandler.ignoredCharacters(text, augmentations);
  891. }
  892. }
  893. /* (non-Javadoc)
  894. * @see com.sun.org.apache.xerces.internal.xni.XMLDTDHandler#internalEntityDecl(java.lang.String, com.sun.org.apache.xerces.internal.xni.XMLString, com.sun.org.apache.xerces.internal.xni.XMLString, com.sun.org.apache.xerces.internal.xni.Augmentations)
  895. */
  896. public void internalEntityDecl(
  897. String name,
  898. XMLString text,
  899. XMLString nonNormalizedText,
  900. Augmentations augmentations)
  901. throws XNIException {
  902. if (fDTDHandler != null) {
  903. fDTDHandler.internalEntityDecl(
  904. name,
  905. text,
  906. nonNormalizedText,
  907. augmentations);
  908. }
  909. }
  910. /* (non-Javadoc)
  911. * @see com.sun.org.apache.xerces.internal.xni.XMLDTDHandler#notationDecl(java.lang.String, com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier, com.sun.org.apache.xerces.internal.xni.Augmentations)
  912. */
  913. public void notationDecl(
  914. String name,
  915. XMLResourceIdentifier identifier,
  916. Augmentations augmentations)
  917. throws XNIException {
  918. this.addNotation(name, identifier, augmentations);
  919. if (fDTDHandler != null) {
  920. fDTDHandler.notationDecl(name, identifier, augmentations);
  921. }
  922. }
  923. /* (non-Javadoc)
  924. * @see com.sun.org.apache.xerces.internal.xni.XMLDTDHandler#setDTDSource(com.sun.org.apache.xerces.internal.xni.parser.XMLDTDSource)
  925. */
  926. public void setDTDSource(XMLDTDSource source) {
  927. fDTDSource = source;
  928. }
  929. /* (non-Javadoc)
  930. * @see com.sun.org.apache.xerces.internal.xni.XMLDTDHandler#startAttlist(java.lang.String, com.sun.org.apache.xerces.internal.xni.Augmentations)
  931. */
  932. public void startAttlist(String elementName, Augmentations augmentations)
  933. throws XNIException {
  934. if (fDTDHandler != null) {
  935. fDTDHandler.startAttlist(elementName, augmentations);
  936. }
  937. }
  938. /* (non-Javadoc)
  939. * @see com.sun.org.apache.xerces.internal.xni.XMLDTDHandler#startConditional(short, com.sun.org.apache.xerces.internal.xni.Augmentations)
  940. */
  941. public void startConditional(short type, Augmentations augmentations)
  942. throws XNIException {
  943. if (fDTDHandler != null) {
  944. fDTDHandler.startConditional(type, augmentations);
  945. }
  946. }
  947. /* (non-Javadoc)
  948. * @see com.sun.org.apache.xerces.internal.xni.XMLDTDHandler#startDTD(com.sun.org.apache.xerces.internal.xni.XMLLocator, com.sun.org.apache.xerces.internal.xni.Augmentations)
  949. */
  950. public void startDTD(XMLLocator locator, Augmentations augmentations)
  951. throws XNIException {
  952. fInDTD = true;
  953. if (fDTDHandler != null) {
  954. fDTDHandler.startDTD(locator, augmentations);
  955. }
  956. }
  957. /* (non-Javadoc)
  958. * @see com.sun.org.apache.xerces.internal.xni.XMLDTDHandler#startExternalSubset(com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier, com.sun.org.apache.xerces.internal.xni.Augmentations)
  959. */
  960. public void startExternalSubset(
  961. XMLResourceIdentifier identifier,
  962. Augmentations augmentations)
  963. throws XNIException {
  964. if (fDTDHandler != null) {
  965. fDTDHandler.startExternalSubset(identifier, augmentations);
  966. }
  967. }
  968. /* (non-Javadoc)
  969. * @see com.sun.org.apache.xerces.internal.xni.XMLDTDHandler#startParameterEntity(java.lang.String, com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier, java.lang.String, com.sun.org.apache.xerces.internal.xni.Augmentations)
  970. */
  971. public void startParameterEntity(
  972. String name,
  973. XMLResourceIdentifier identifier,
  974. String encoding,
  975. Augmentations augmentations)
  976. throws XNIException {
  977. if (fDTDHandler != null) {
  978. fDTDHandler.startParameterEntity(
  979. name,
  980. identifier,
  981. encoding,
  982. augmentations);
  983. }
  984. }
  985. /* (non-Javadoc)
  986. * @see com.sun.org.apache.xerces.internal.xni.XMLDTDHandler#unparsedEntityDecl(java.lang.String, com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier, java.lang.String, com.sun.org.apache.xerces.internal.xni.Augmentations)
  987. */
  988. public void unparsedEntityDecl(
  989. String name,
  990. XMLResourceIdentifier identifier,
  991. String notation,
  992. Augmentations augmentations)
  993. throws XNIException {
  994. this.addUnparsedEntity(name, identifier, notation, augmentations);
  995. if (fDTDHandler != null) {
  996. fDTDHandler.unparsedEntityDecl(
  997. name,
  998. identifier,
  999. notation,
  1000. augmentations);
  1001. }
  1002. }
  1003. /* (non-Javadoc)
  1004. * @see com.sun.org.apache.xerces.internal.xni.parser.XMLDTDSource#getDTDHandler()
  1005. */
  1006. public XMLDTDHandler getDTDHandler() {
  1007. return fDTDHandler;
  1008. }
  1009. /* (non-Javadoc)
  1010. * @see com.sun.org.apache.xerces.internal.xni.parser.XMLDTDSource#setDTDHandler(com.sun.org.apache.xerces.internal.xni.XMLDTDHandler)
  1011. */
  1012. public void setDTDHandler(XMLDTDHandler handler) {
  1013. fDTDHandler = handler;
  1014. }
  1015. // XIncludeHandler methods
  1016. private void setErrorReporter(XMLErrorReporter reporter) {
  1017. fErrorReporter = reporter;
  1018. if (fErrorReporter != null) {
  1019. fErrorReporter.putMessageFormatter(
  1020. XIncludeMessageFormatter.XINCLUDE_DOMAIN,
  1021. new XIncludeMessageFormatter());
  1022. // this ensures the proper location is displayed in error messages
  1023. if (fDocLocation != null) {
  1024. fErrorReporter.setDocumentLocator(fDocLocation);
  1025. }
  1026. }
  1027. }
  1028. protected void handleFallbackElement() {
  1029. setSawInclude(fDepth, false);
  1030. fNamespaceContext.setContextInvalid();
  1031. if (!getSawInclude(fDepth - 1)) {
  1032. reportFatalError("FallbackParent");
  1033. }
  1034. if (getSawFallback(fDepth)) {
  1035. reportFatalError("MultipleFallbacks");
  1036. }
  1037. else {
  1038. setSawFallback(fDepth, true);
  1039. }
  1040. // Either the state is STATE_EXPECT_FALLBACK or it's STATE_IGNORE.
  1041. // If we're ignoring, we want to stay ignoring. But if we're expecting this fallback element,
  1042. // we want to signal that we should process the children.
  1043. if (getState() == STATE_EXPECT_FALLBACK) {
  1044. setState(STATE_NORMAL_PROCESSING);
  1045. }
  1046. }
  1047. protected boolean handleIncludeElement(XMLAttributes attributes)
  1048. throws XNIException {
  1049. setSawInclude(fDepth, true);
  1050. fNamespaceContext.setContextInvalid();
  1051. if (getSawInclude(fDepth - 1)) {
  1052. reportFatalError("IncludeChild", new Object[] { XINCLUDE_INCLUDE });
  1053. }
  1054. if (getState() == STATE_IGNORE)
  1055. return true;
  1056. // TODO: does Java use IURIs by default?
  1057. // [Definition: An internationalized URI reference, or IURI, is a URI reference that directly uses [Unicode] characters.]
  1058. // TODO: figure out what section 4.1.1 of the XInclude spec is talking about
  1059. // has to do with disallowed ASCII character escaping
  1060. // this ties in with the above IURI section, but I suspect Java already does it
  1061. String href = attributes.getValue(XINCLUDE_ATTR_HREF);
  1062. String parse = attributes.getValue(XINCLUDE_ATTR_PARSE);
  1063. String xpointerPart = attributes.getValue(XPOINTER);
  1064. String accept = attributes.getValue(XINCLUDE_ATTR_ACCEPT);
  1065. String acceptLanguage = attributes.getValue(XINCLUDE_ATTR_ACCEPT_LANGUAGE);
  1066. if (href == null && xpointerPart == null) {
  1067. reportFatalError("XpointerMissing");
  1068. }
  1069. if (parse == null) {
  1070. parse = XINCLUDE_PARSE_XML;
  1071. }
  1072. boolean xpointer = false;
  1073. String parserName = null;
  1074. //Ignore fragment identifiers, implementation specific as per spec.
  1075. if( href.indexOf("#")!=-1 )
  1076. href = href.substring(0,href.indexOf("#"));
  1077. if ( xpointerPart != null && parse.equals(XINCLUDE_PARSE_XML))
  1078. xpointer = true;
  1079. // Verify that if an accept and/or an accept-language attribute exist
  1080. // that the value(s) don't contain disallowed characters.
  1081. if (accept != null && !isValidInHTTPHeader(accept)) {
  1082. reportFatalError("AcceptMalformed", null);
  1083. }
  1084. if (acceptLanguage != null && !isValidInHTTPHeader(acceptLanguage)) {
  1085. reportFatalError("AcceptLanguageMalformed", null);
  1086. }
  1087. XMLInputSource includedSource = null;
  1088. if (fEntityResolver != null) {
  1089. try {
  1090. XMLResourceIdentifier resourceIdentifier =
  1091. new XMLResourceIdentifierImpl(
  1092. null,
  1093. href,
  1094. fCurrentBaseURI.getExpandedSystemId(),
  1095. XMLEntityManager.expandSystemId(
  1096. href,
  1097. fCurrentBaseURI.getExpandedSystemId(),
  1098. false));
  1099. includedSource =
  1100. fEntityResolver.resolveEntity(resourceIdentifier);
  1101. } catch (IOException e) {
  1102. reportResourceError(
  1103. "XMLResourceError",
  1104. new Object[] { href, e.getMessage()});
  1105. return false;
  1106. }
  1107. }
  1108. if (includedSource == null) {
  1109. includedSource =
  1110. new XIncludeInputSource(
  1111. null,
  1112. href,
  1113. fCurrentBaseURI.getExpandedSystemId());
  1114. }
  1115. if(parse.equals(XINCLUDE_PARSE_XML) && xpointer ){
  1116. if(fXPointerFramework == null){
  1117. fXPointerFramework = new XPointerFramework();
  1118. fXPointerFramework.setXPointerSchema(fXPointerSchema);
  1119. }else{
  1120. fXPointerFramework.reset();
  1121. fXPointerFramework.setXPointerSchema(fXPointerSchema);
  1122. }
  1123. parserName = XPOINTER_DEFAULT_CONFIGURATION;
  1124. fChildConfig = createXPointerParser();
  1125. fXPointerFramework.setSchemaPointer(xpointerPart);
  1126. // we don't want a schema validator on the new pipeline,
  1127. // so we set it to false, regardless of what was copied above
  1128. /* fChildConfig.setFeature(
  1129. Constants.XERCES_FEATURE_PREFIX
  1130. + Constants.SCHEMA_VALIDATION_FEATURE,
  1131. false);*/
  1132. //-Revisit and clean up this piece of unclean code.
  1133. XPointerSchema fXPointerSchemaS;
  1134. if((fXPointerSchemaS = fXPointerFramework.getNextXPointerSchema()) == null && fXPointerFramework.getSchemaCount() == 0){
  1135. fNamespaceContext.pushScope();
  1136. fXPointerSchemaS = fXPointerFramework.getDefaultSchema();
  1137. fXPointerSchemaS.setXPointerSchemaPointer(xpointerPart);
  1138. processSchema(fXPointerSchemaS,includedSource);
  1139. /*
  1140. Object sch = null;
  1141. if(!fXPointerFramework.fSchemaNotAvailable.empty())
  1142. sch = fXPointerFramework.fSchemaNotAvailable.pop();
  1143. reportFatalError("NO_XPointerSchema", new Object[] {sch});
  1144. */
  1145. }else {
  1146. try {
  1147. fNamespaceContext.pushScope();
  1148. if(fXPointerSchemaS != null && processSchema(fXPointerSchemaS,includedSource)){
  1149. ;
  1150. }else{
  1151. for (int i=fXPointerFramework.getCurrentPointer(); i <=fXPointerFramework.getSchemaCount();i++){
  1152. fXPointerSchemaS = fXPointerFramework.getNextXPointerSchema();
  1153. if(fXPointerSchemaS != null && processSchema(fXPointerSchemaS,includedSource)){
  1154. break;
  1155. }
  1156. }
  1157. }
  1158. }
  1159. catch (XNIException e) {
  1160. reportFatalError("XMLParseError");
  1161. }
  1162. finally {
  1163. fNamespaceContext.popScope();
  1164. }
  1165. }
  1166. }
  1167. else if (parse.equals(XINCLUDE_PARSE_XML)) {
  1168. // Instead of always creating a new configuration, the first one can be reused
  1169. //if (fChildConfig == null) {
  1170. parserName = XINCLUDE_DEFAULT_CONFIGURATION;
  1171. fChildConfig =
  1172. (XMLParserConfiguration)ObjectFactory.newInstance(
  1173. parserName,
  1174. ObjectFactory.findClassLoader(),
  1175. true);
  1176. // use the same error reporter, entity resolver, and security manager.
  1177. if (fErrorReporter != null) fChildConfig.setProperty(ERROR_REPORTER, fErrorReporter);
  1178. if (fEntityResolver != null) fChildConfig.setProperty(ENTITY_RESOLVER, fEntityResolver);
  1179. if (fSecurityManager != null) fChildConfig.setProperty(SECURITY_MANAGER, fSecurityManager);
  1180. // use the same namespace context
  1181. fChildConfig.setProperty(
  1182. Constants.XERCES_PROPERTY_PREFIX
  1183. + Constants.NAMESPACE_CONTEXT_PROPERTY,
  1184. fNamespaceContext);
  1185. XIncludeHandler newHandler =
  1186. (XIncludeHandler)fChildConfig.getProperty(
  1187. Constants.XERCES_PROPERTY_PREFIX
  1188. + Constants.XINCLUDE_HANDLER_PROPERTY);
  1189. newHandler.setParent(this);
  1190. newHandler.setDocumentHandler(this.getDocumentHandler());
  1191. //}
  1192. // set all features on parserConfig to match this parser configuration
  1193. copyFeatures(fSettings, fChildConfig);
  1194. // we don't want a schema validator on the new pipeline,
  1195. // so we set it to false, regardless of what was copied above
  1196. fChildConfig.setFeature(
  1197. Constants.XERCES_FEATURE_PREFIX
  1198. + Constants.SCHEMA_VALIDATION_FEATURE,
  1199. false);
  1200. fChildConfig.setFeature(
  1201. Constants.XERCES_FEATURE_PREFIX
  1202. + Constants.XINCLUDE_AWARE,
  1203. true);
  1204. try {
  1205. fNamespaceContext.pushScope();
  1206. includedSource = setHttpProperties(includedSource,attributes);
  1207. fChildConfig.parse(includedSource);
  1208. // necessary to make sure proper location is reported in errors
  1209. if (fErrorReporter != null) {
  1210. fErrorReporter.setDocumentLocator(fDocLocation);
  1211. }
  1212. }
  1213. catch (XNIException e) {
  1214. // necessary to make sure proper location is reported in errors
  1215. if (fErrorReporter != null) {
  1216. fErrorReporter.setDocumentLocator(fDocLocation);
  1217. }
  1218. reportFatalError("XMLParseError", new Object[] { href });
  1219. }
  1220. catch (IOException e) {
  1221. // necessary to make sure proper location is reported in errors
  1222. if (fErrorReporter != null) {
  1223. fErrorReporter.setDocumentLocator(fDocLocation);
  1224. }
  1225. // An IOException indicates that we had trouble reading the file, not
  1226. // that it was an invalid XML file. So we send a resource error, not a
  1227. // fatal error.
  1228. reportResourceError(
  1229. "XMLResourceError",
  1230. new Object[] { href, e.getMessage()});
  1231. return false;
  1232. }
  1233. finally {
  1234. fNamespaceContext.popScope();
  1235. }
  1236. }
  1237. else if (parse.equals(XINCLUDE_PARSE_TEXT)) {
  1238. // we only care about encoding for parse="text"
  1239. String encoding = attributes.getValue(XINCLUDE_ATTR_ENCODING);
  1240. includedSource.setEncoding(encoding);
  1241. XIncludeTextReader reader = null;
  1242. try {
  1243. if (fIsXML11) {
  1244. reader = new XInclude11TextReader(includedSource, this);
  1245. }
  1246. else {
  1247. reader = new XIncludeTextReader(includedSource, this);
  1248. }
  1249. if (includedSource.getCharacterStream() == null
  1250. && includedSource.getByteStream() == null) {
  1251. reader.setHttpProperties(accept, acceptLanguage);
  1252. }
  1253. reader.setErrorReporter(fErrorReporter);
  1254. reader.parse();
  1255. }
  1256. // encoding errors
  1257. catch (MalformedByteSequenceException ex) {
  1258. fErrorReporter.reportError(ex.getDomain(), ex.getKey(),
  1259. ex.getArguments(), XMLErrorReporter.SEVERITY_FATAL_ERROR);
  1260. }
  1261. catch (CharConversionException e) {
  1262. fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
  1263. "CharConversionFailure", null, XMLErrorReporter.SEVERITY_FATAL_ERROR);
  1264. }
  1265. catch (IOException e) {
  1266. reportResourceError(
  1267. "TextResourceError",
  1268. new Object[] { href, e.getMessage()});
  1269. return false;
  1270. }
  1271. finally {
  1272. if (reader != null) {
  1273. try {
  1274. reader.close();
  1275. }
  1276. catch (IOException e) {
  1277. reportResourceError(
  1278. "TextResourceError",
  1279. new Object[] { href, e.getMessage()});
  1280. return false;
  1281. }
  1282. }
  1283. }
  1284. }
  1285. else {
  1286. reportFatalError("InvalidParseValue", new Object[] { parse });
  1287. }
  1288. return true;
  1289. }
  1290. /**
  1291. * Returns true if the element has the namespace "http://www.w3.org/2001/XInclude"
  1292. * @param element the element to check
  1293. * @return true if the element has the namespace "http://www.w3.org/2001/XInclude"
  1294. */
  1295. protected boolean hasXIncludeNamespace(QName element) {
  1296. // REVISIT: The namespace of this element should be bound
  1297. // already. Why are we looking it up from the namespace
  1298. // context? -- mrglavas
  1299. return element.uri == XINCLUDE_NS_URI
  1300. || fNamespaceContext.getURI(element.prefix) == XINCLUDE_NS_URI;
  1301. }
  1302. /**
  1303. * Checks if the element is an <include> element. The element must have
  1304. * the XInclude namespace, and a local name of "include".
  1305. *
  1306. * @param element the element to check
  1307. * @return true if the element is an <include> element
  1308. * @see #hasXIncludeNamespace(QName)
  1309. */
  1310. protected boolean isIncludeElement(QName element) {
  1311. return element.localpart.equals(XINCLUDE_INCLUDE) &&
  1312. hasXIncludeNamespace(element);
  1313. }
  1314. /**
  1315. * Checks if the element is an <fallback> element. The element must have
  1316. * the XInclude namespace, and a local name of "fallback".
  1317. *
  1318. * @param element the element to check
  1319. * @return true if the element is an <fallback; element
  1320. * @see #hasXIncludeNamespace(QName)
  1321. */
  1322. protected boolean isFallbackElement(QName element) {
  1323. return element.localpart.equals(XINCLUDE_FALLBACK) &&
  1324. hasXIncludeNamespace(element);
  1325. }
  1326. /**
  1327. * Returns true if the current [base URI] is the same as the [base URI] that
  1328. * was in effect on the include parent. This method should <em>only</em> be called
  1329. * when the current element is a top level included element, i.e. the direct child
  1330. * of a fallback element, or the root elements in an included document.
  1331. * The "include parent" is the element which, in the result infoset, will be the
  1332. * direct parent of the current element.
  1333. * @return true if the [base URIs] are the same string
  1334. */
  1335. protected boolean sameBaseURIAsIncludeParent() {
  1336. String parentBaseURI = getIncludeParentBaseURI();
  1337. String baseURI = fCurrentBaseURI.getExpandedSystemId();
  1338. // REVISIT: should we use File#sameFile() ?
  1339. // I think the benefit of using it is that it resolves host names
  1340. // instead of just doing a string comparison.
  1341. // TODO: [base URI] is still an open issue with the working group.
  1342. // They're deciding if xml:base should be added if the [base URI] is different in terms
  1343. // of resolving relative references, or if it should be added if they are different at all.
  1344. // Revisit this after a final decision has been made.
  1345. // The decision also affects whether we output the file name of the URI, or just the path.
  1346. return parentBaseURI != null && parentBaseURI.equals(baseURI);
  1347. }
  1348. /**
  1349. * Checks if the file indicated by the given XMLLocator has already been included
  1350. * in the current stack.
  1351. * @param includedSource the source to check for inclusion
  1352. * @return true if the source has already been included
  1353. */
  1354. protected boolean searchForRecursiveIncludes(XMLLocator includedSource) {
  1355. String includedSystemId = includedSource.getExpandedSystemId();
  1356. if (includedSystemId == null) {
  1357. try {
  1358. includedSystemId =
  1359. XMLEntityManager.expandSystemId(
  1360. includedSource.getLiteralSystemId(),
  1361. includedSource.getBaseSystemId(),
  1362. false);
  1363. }
  1364. catch (MalformedURIException e) {
  1365. reportFatalError("ExpandedSystemId");
  1366. }
  1367. }
  1368. if (includedSystemId.equals(fCurrentBaseURI.getExpandedSystemId())) {
  1369. return true;
  1370. }
  1371. if (fParentXIncludeHandler == null) {
  1372. return false;
  1373. }
  1374. return fParentXIncludeHandler.searchForRecursiveIncludes(
  1375. includedSource);
  1376. }
  1377. /**
  1378. * Returns true if the current element is a top level included item. This means
  1379. * it's either the child of a fallback element, or the top level item in an
  1380. * included document
  1381. * @return true if the current element is a top level included item
  1382. */
  1383. protected boolean isTopLevelIncludedItem() {
  1384. return isTopLevelIncludedItemViaInclude()
  1385. || isTopLevelIncludedItemViaFallback();
  1386. }
  1387. protected boolean isTopLevelIncludedItemViaInclude() {
  1388. return fDepth == 1 && !isRootDocument();
  1389. }
  1390. protected boolean isTopLevelIncludedItemViaFallback() {
  1391. // Technically, this doesn't check if the parent was a fallback, it also
  1392. // would return true if any of the parent's sibling elements were fallbacks.
  1393. // However, this doesn't matter, since we will always be ignoring elements
  1394. // whose parent's siblings were fallbacks.
  1395. return getSawFallback(fDepth - 1);
  1396. }
  1397. /**
  1398. * Processes the XMLAttributes object of startElement() calls. Performs the following tasks:
  1399. * <ul>
  1400. * <li> If the element is a top level included item whose [base URI] is different from the
  1401. * [base URI] of the include parent, then an xml:base attribute is added to specify the
  1402. * true [base URI]
  1403. * <li> For all namespace prefixes which are in-scope in an included item, but not in scope
  1404. * in the include parent, a xmlns:prefix attribute is added
  1405. * <li> For all attributes with a type of ENTITY, ENTITIES or NOTATIONS, the notations and
  1406. * unparsed entities are processed as described in the spec, sections 4.5.1 and 4.5.2
  1407. * </ul>
  1408. * @param attributes
  1409. * @return
  1410. */
  1411. protected XMLAttributes processAttributes(XMLAttributes attributes) {
  1412. if (isTopLevelIncludedItem()) {
  1413. // Modify attributes to fix the base URI (spec 4.5.5).
  1414. // We only do it to top level included elements, which have a different
  1415. // base URI than their include parent.
  1416. if (!sameBaseURIAsIncludeParent()) {
  1417. if (attributes == null) {
  1418. attributes = new XMLAttributesImpl();
  1419. }
  1420. // This causes errors with schema validation, if the schema doesn't
  1421. // specify that these elements can have an xml:base attribute
  1422. // TODO: add a user option to turn this off?
  1423. String uri = null;
  1424. try {
  1425. uri = this.getRelativeBaseURI();
  1426. }
  1427. catch (MalformedURIException e) {
  1428. // this shouldn't ever happen, since by definition, we had to traverse
  1429. // the same URIs to even get to this place
  1430. uri = fCurrentBaseURI.getExpandedSystemId();
  1431. }
  1432. int index =
  1433. attributes.addAttribute(
  1434. XML_BASE_QNAME,
  1435. XMLSymbols.fCDATASymbol,
  1436. uri);
  1437. attributes.setSpecified(index, true);
  1438. }
  1439. // Modify attributes of included items to do namespace-fixup. (spec 4.5.4)
  1440. Enumeration inscopeNS = fNamespaceContext.getAllPrefixes();
  1441. while (inscopeNS.hasMoreElements()) {
  1442. String prefix = (String)inscopeNS.nextElement();
  1443. String parentURI =
  1444. fNamespaceContext.getURIFromIncludeParent(prefix);
  1445. String uri = fNamespaceContext.getURI(prefix);
  1446. if (parentURI != uri && attributes != null) {
  1447. if (prefix == XMLSymbols.EMPTY_STRING) {
  1448. if (attributes
  1449. .getValue(
  1450. NamespaceContext.XMLNS_URI,
  1451. XMLSymbols.PREFIX_XMLNS)
  1452. == null) {
  1453. if (attributes == null) {
  1454. attributes = new XMLAttributesImpl();
  1455. }
  1456. QName ns = (QName)NEW_NS_ATTR_QNAME.clone();
  1457. ns.localpart = XMLSymbols.PREFIX_XMLNS;
  1458. ns.rawname = XMLSymbols.PREFIX_XMLNS;
  1459. attributes.addAttribute(
  1460. ns,
  1461. XMLSymbols.fCDATASymbol,
  1462. uri);
  1463. }
  1464. }
  1465. else if (
  1466. attributes.getValue(NamespaceContext.XMLNS_URI, prefix)
  1467. == null) {
  1468. if (attributes == null) {
  1469. attributes = new XMLAttributesImpl();
  1470. }
  1471. QName ns = (QName)NEW_NS_ATTR_QNAME.clone();
  1472. ns.localpart = prefix;
  1473. ns.rawname += prefix;
  1474. attributes.addAttribute(
  1475. ns,
  1476. XMLSymbols.fCDATASymbol,
  1477. uri);
  1478. }
  1479. }
  1480. }
  1481. }
  1482. if (attributes != null) {
  1483. int length = attributes.getLength();
  1484. for (int i = 0; i < length; i++) {
  1485. String type = attributes.getType(i);
  1486. String value = attributes.getValue(i);
  1487. if (type == XMLSymbols.fENTITYSymbol) {
  1488. this.checkUnparsedEntity(value);
  1489. }
  1490. if (type == XMLSymbols.fENTITIESSymbol) {
  1491. // 4.5.1 - Unparsed Entities
  1492. StringTokenizer st = new StringTokenizer(value);
  1493. while (st.hasMoreTokens()) {
  1494. String entName = st.nextToken();
  1495. this.checkUnparsedEntity(entName);
  1496. }
  1497. }
  1498. else if (type == XMLSymbols.fNOTATIONSymbol) {
  1499. // 4.5.2 - Notations
  1500. this.checkNotation(value);
  1501. }
  1502. /* We actually don't need to do anything for 4.5.3, because at this stage the
  1503. * value of the attribute is just a string. It will be taken care of later
  1504. * in the pipeline, when the IDREFs are actually resolved against IDs.
  1505. *
  1506. * if (type == XMLSymbols.fIDREFSymbol || type == XMLSymbols.fIDREFSSymbol) { }
  1507. */
  1508. }
  1509. }
  1510. return attributes;
  1511. }
  1512. /**
  1513. * Returns a URI, relative to the include parent's base URI, of the current
  1514. * [base URI]. For instance, if the current [base URI] was "dir1/dir2/file.xml"
  1515. * and the include parent's [base URI] was "dir/", this would return "dir2/file.xml".
  1516. * @return the relative URI
  1517. */
  1518. protected String getRelativeBaseURI() throws MalformedURIException {
  1519. int includeParentDepth = getIncludeParentDepth();
  1520. String relativeURI = this.getRelativeURI(includeParentDepth);
  1521. if (isRootDocument()) {
  1522. return relativeURI;
  1523. }
  1524. else {
  1525. if (relativeURI.equals("")) {
  1526. relativeURI = fCurrentBaseURI.getLiteralSystemId();
  1527. }
  1528. if (includeParentDepth == 0) {
  1529. if (fParentRelativeURI == null) {
  1530. fParentRelativeURI =
  1531. fParentXIncludeHandler.getRelativeBaseURI();
  1532. }
  1533. if (fParentRelativeURI.equals("")) {
  1534. return relativeURI;
  1535. }
  1536. URI uri = new URI("file", fParentRelativeURI);
  1537. uri = new URI(uri, relativeURI);
  1538. return uri.getPath();
  1539. }
  1540. else {
  1541. return relativeURI;
  1542. }
  1543. }
  1544. }
  1545. /**
  1546. * Returns the [base URI] of the include parent.
  1547. * @return the base URI of the include parent.
  1548. */
  1549. private String getIncludeParentBaseURI() {
  1550. int depth = getIncludeParentDepth();
  1551. if (!isRootDocument() && depth == 0) {
  1552. return fParentXIncludeHandler.getIncludeParentBaseURI();
  1553. }
  1554. else {
  1555. return this.getBaseURI(depth);
  1556. }
  1557. }
  1558. /**
  1559. * Returns the depth of the include parent. Here, the include parent is
  1560. * calculated as the last non-include or non-fallback element. It is assumed
  1561. * this method is called when the current element is a top level included item.
  1562. * Returning 0 indicates that the top level element in this document
  1563. * was an include element.
  1564. * @return the depth of the top level include element
  1565. */
  1566. private int getIncludeParentDepth() {
  1567. // We don't start at fDepth, since it is either the top level included item,
  1568. // or an include element, when this method is called.
  1569. for (int i = fDepth - 1; i >= 0; i--) {
  1570. // This technically might not always return the first non-include/fallback
  1571. // element that it comes to, since sawFallback() returns true if a fallback
  1572. // was ever encountered at that depth. However, if a fallback was encountered
  1573. // at that depth, and it wasn't the direct descendant of the current element
  1574. // then we can't be in a situation where we're calling this method (because
  1575. // we'll always be in STATE_IGNORE)
  1576. if (!getSawInclude(i) && !getSawFallback(i)) {
  1577. return i;
  1578. }
  1579. }
  1580. // shouldn't get here, since depth 0 should never have an include element or
  1581. // a fallback element
  1582. return 0;
  1583. }
  1584. /**
  1585. * Modify the augmentations. Add an [included] infoset item, if the current
  1586. * element is a top level included item.
  1587. * @param augs the Augmentations to modify.
  1588. * @return the modified Augmentations
  1589. */
  1590. protected Augmentations modifyAugmentations(Augmentations augs) {
  1591. return modifyAugmentations(augs, false);
  1592. }
  1593. /**
  1594. * Modify the augmentations. Add an [included] infoset item, if <code>force</code>
  1595. * is true, or if the current element is a top level included item.
  1596. * @param augs the Augmentations to modify.
  1597. * @param force whether to force modification
  1598. * @return the modified Augmentations
  1599. */
  1600. protected Augmentations modifyAugmentations(
  1601. Augmentations augs,
  1602. boolean force) {
  1603. if (force || isTopLevelIncludedItem()) {
  1604. if (augs == null) {
  1605. augs = new AugmentationsImpl();
  1606. }
  1607. augs.putItem(XINCLUDE_INCLUDED, Boolean.TRUE);
  1608. }
  1609. return augs;
  1610. }
  1611. protected int getState(int depth) {
  1612. return fState[depth];
  1613. }
  1614. protected int getState() {
  1615. return fState[fDepth];
  1616. }
  1617. protected void setState(int state) {
  1618. if (fDepth >= fState.length) {
  1619. int[] newarray = new int[fDepth * 2];
  1620. System.arraycopy(fState, 0, newarray, 0, fState.length);
  1621. fState = newarray;
  1622. }
  1623. fState[fDepth] = state;
  1624. }
  1625. /**
  1626. * Records that an <fallback> was encountered at the specified depth,
  1627. * as an ancestor of the current element, or as a sibling of an ancestor of the
  1628. * current element.
  1629. *
  1630. * @param depth
  1631. * @param val
  1632. */
  1633. protected void setSawFallback(int depth, boolean val) {
  1634. if (depth >= fSawFallback.length) {
  1635. boolean[] newarray = new boolean[depth * 2];
  1636. System.arraycopy(fSawFallback, 0, newarray, 0, fSawFallback.length);
  1637. fSawFallback = newarray;
  1638. }
  1639. fSawFallback[depth] = val;
  1640. }
  1641. /**
  1642. * Returns whether an <fallback> was encountered at the specified depth,
  1643. * as an ancestor of the current element, or as a sibling of an ancestor of the
  1644. * current element.
  1645. *
  1646. * @param depth
  1647. */
  1648. protected boolean getSawFallback(int depth) {
  1649. if (depth >= fSawFallback.length) {
  1650. return false;
  1651. }
  1652. return fSawFallback[depth];
  1653. }
  1654. /**
  1655. * Records that an <include> was encountered at the specified depth,
  1656. * as an ancestor of the current item.
  1657. *
  1658. * @param depth
  1659. * @param val
  1660. */
  1661. protected void setSawInclude(int depth, boolean val) {
  1662. if (depth >= fSawInclude.length) {
  1663. boolean[] newarray = new boolean[depth * 2];
  1664. System.arraycopy(fSawInclude, 0, newarray, 0, fSawInclude.length);
  1665. fSawInclude = newarray;
  1666. }
  1667. fSawInclude[depth] = val;
  1668. }
  1669. /**
  1670. * Return whether an <include> was encountered at the specified depth,
  1671. * as an ancestor of the current item.
  1672. *
  1673. * @param depth
  1674. * @return
  1675. */
  1676. protected boolean getSawInclude(int depth) {
  1677. if (depth >= fSawInclude.length) {
  1678. return false;
  1679. }
  1680. return fSawInclude[depth];
  1681. }
  1682. protected void reportResourceError(String key) {
  1683. this.reportFatalError(key, null);
  1684. }
  1685. protected void reportResourceError(String key, Object[] args) {
  1686. this.reportError(key, args, XMLErrorReporter.SEVERITY_WARNING);
  1687. }
  1688. protected void reportFatalError(String key) {
  1689. this.reportFatalError(key, null);
  1690. }
  1691. protected void reportFatalError(String key, Object[] args) {
  1692. this.reportError(key, args, XMLErrorReporter.SEVERITY_FATAL_ERROR);
  1693. }
  1694. private void reportError(String key, Object[] args, short severity) {
  1695. if (fErrorReporter != null) {
  1696. fErrorReporter.reportError(
  1697. XIncludeMessageFormatter.XINCLUDE_DOMAIN,
  1698. key,
  1699. args,
  1700. severity);
  1701. }
  1702. // we won't worry about when error reporter is null, since there should always be
  1703. // at least the default error reporter
  1704. }
  1705. /**
  1706. * Set the parent of this XIncludeHandler in the tree
  1707. * @param parent
  1708. */
  1709. protected void setParent(XIncludeHandler parent) {
  1710. fParentXIncludeHandler = parent;
  1711. }
  1712. // used to know whether to pass declarations to the document handler
  1713. protected boolean isRootDocument() {
  1714. return fParentXIncludeHandler == null;
  1715. }
  1716. /**
  1717. * Caches an unparsed entity.
  1718. * @param name the name of the unparsed entity
  1719. * @param identifier the location of the unparsed entity
  1720. * @param augmentations any Augmentations that were on the original unparsed entity declaration
  1721. */
  1722. protected void addUnparsedEntity(
  1723. String name,
  1724. XMLResourceIdentifier identifier,
  1725. String notation,
  1726. Augmentations augmentations) {
  1727. UnparsedEntity ent = new UnparsedEntity();
  1728. ent.name = name;
  1729. ent.systemId = identifier.getLiteralSystemId();
  1730. ent.publicId = identifier.getPublicId();
  1731. ent.baseURI = identifier.getBaseSystemId();
  1732. ent.notation = notation;
  1733. ent.augmentations = augmentations;
  1734. fUnparsedEntities.add(ent);
  1735. }
  1736. /**
  1737. * Caches a notation.
  1738. * @param name the name of the notation
  1739. * @param identifier the location of the notation
  1740. * @param augmentations any Augmentations that were on the original notation declaration
  1741. */
  1742. protected void addNotation(
  1743. String name,
  1744. XMLResourceIdentifier identifier,
  1745. Augmentations augmentations) {
  1746. Notation not = new Notation();
  1747. not.name = name;
  1748. not.systemId = identifier.getLiteralSystemId();
  1749. not.publicId = identifier.getPublicId();
  1750. not.baseURI = identifier.getBaseSystemId();
  1751. not.augmentations = augmentations;
  1752. fNotations.add(not);
  1753. }
  1754. /**
  1755. * Checks if an UnparsedEntity with the given name was declared in the DTD of the document
  1756. * for the current pipeline. If so, then the notation for the UnparsedEntity is checked.
  1757. * If that turns out okay, then the UnparsedEntity is passed to the root pipeline to
  1758. * be checked for conflicts, and sent to the root DTDHandler.
  1759. *
  1760. * @param entName the name of the UnparsedEntity to check
  1761. */
  1762. protected void checkUnparsedEntity(String entName) {
  1763. UnparsedEntity ent = new UnparsedEntity();
  1764. ent.name = entName;
  1765. int index = fUnparsedEntities.indexOf(ent);
  1766. if (index != -1) {
  1767. ent = (UnparsedEntity)fUnparsedEntities.get(index);
  1768. // first check the notation of the unparsed entity
  1769. checkNotation(ent.notation);
  1770. checkAndSendUnparsedEntity(ent);
  1771. }
  1772. }
  1773. /**
  1774. * Checks if a Notation with the given name was declared in the DTD of the document
  1775. * for the current pipeline. If so, that Notation is passed to the root pipeline to
  1776. * be checked for conflicts, and sent to the root DTDHandler
  1777. *
  1778. * @param notName the name of the Notation to check
  1779. */
  1780. protected void checkNotation(String notName) {
  1781. Notation not = new Notation();
  1782. not.name = notName;
  1783. int index = fNotations.indexOf(not);
  1784. if (index != -1) {
  1785. not = (Notation)fNotations.get(index);
  1786. checkAndSendNotation(not);
  1787. }
  1788. }
  1789. /**
  1790. * The purpose of this method is to check if an UnparsedEntity conflicts with a previously
  1791. * declared entity in the current pipeline stack. If there is no conflict, the
  1792. * UnparsedEntity is sent by the root pipeline.
  1793. *
  1794. * @param ent the UnparsedEntity to check for conflicts
  1795. */
  1796. protected void checkAndSendUnparsedEntity(UnparsedEntity ent) {
  1797. if (isRootDocument()) {
  1798. int index = fUnparsedEntities.indexOf(ent);
  1799. if (index == -1) {
  1800. // There is no unparsed entity with the same name that we have sent.
  1801. // Calling unparsedEntityDecl() will add the entity to our local store,
  1802. // and also send the unparsed entity to the DTDHandler
  1803. XMLResourceIdentifier id =
  1804. new XMLResourceIdentifierImpl(
  1805. ent.publicId,
  1806. ent.systemId,
  1807. ent.baseURI,
  1808. null);
  1809. this.addUnparsedEntity(
  1810. ent.name,
  1811. id,
  1812. ent.notation,
  1813. ent.augmentations);
  1814. if (fSendUEAndNotationEvents && fDTDHandler != null) {
  1815. fDTDHandler.unparsedEntityDecl(
  1816. ent.name,
  1817. id,
  1818. ent.notation,
  1819. ent.augmentations);
  1820. }
  1821. }
  1822. else {
  1823. UnparsedEntity localEntity =
  1824. (UnparsedEntity)fUnparsedEntities.get(index);
  1825. if (!ent.isDuplicate(localEntity)) {
  1826. reportFatalError(
  1827. "NonDuplicateUnparsedEntity",
  1828. new Object[] { ent.name });
  1829. }
  1830. }
  1831. }
  1832. else {
  1833. fParentXIncludeHandler.checkAndSendUnparsedEntity(ent);
  1834. }
  1835. }
  1836. /**
  1837. * The purpose of this method is to check if a Notation conflicts with a previously
  1838. * declared notation in the current pipeline stack. If there is no conflict, the
  1839. * Notation is sent by the root pipeline.
  1840. *
  1841. * @param not the Notation to check for conflicts
  1842. */
  1843. protected void checkAndSendNotation(Notation not) {
  1844. if (isRootDocument()) {
  1845. int index = fNotations.indexOf(not);
  1846. if (index == -1) {
  1847. // There is no notation with the same name that we have sent.
  1848. XMLResourceIdentifier id =
  1849. new XMLResourceIdentifierImpl(
  1850. not.publicId,
  1851. not.systemId,
  1852. not.baseURI,
  1853. null);
  1854. this.addNotation(not.name, id, not.augmentations);
  1855. if (fSendUEAndNotationEvents && fDTDHandler != null) {
  1856. fDTDHandler.notationDecl(not.name, id, not.augmentations);
  1857. }
  1858. }
  1859. else {
  1860. Notation localNotation = (Notation)fNotations.get(index);
  1861. if (!not.isDuplicate(localNotation)) {
  1862. reportFatalError(
  1863. "NonDuplicateNotation",
  1864. new Object[] { not.name });
  1865. }
  1866. }
  1867. }
  1868. else {
  1869. fParentXIncludeHandler.checkAndSendNotation(not);
  1870. }
  1871. }
  1872. // It would be nice if we didn't have to repeat code like this, but there's no interface that has
  1873. // setFeature() and addRecognizedFeatures() that the objects have in common.
  1874. protected void copyFeatures(
  1875. XMLComponentManager from,
  1876. ParserConfigurationSettings to) {
  1877. Enumeration features = Constants.getXercesFeatures();
  1878. copyFeatures1(features, Constants.XERCES_FEATURE_PREFIX, from, to);
  1879. features = Constants.getSAXFeatures();
  1880. copyFeatures1(features, Constants.SAX_FEATURE_PREFIX, from, to);
  1881. }
  1882. protected void copyFeatures(
  1883. XMLComponentManager from,
  1884. XMLParserConfiguration to) {
  1885. Enumeration features = Constants.getXercesFeatures();
  1886. copyFeatures1(features, Constants.XERCES_FEATURE_PREFIX, from, to);
  1887. features = Constants.getSAXFeatures();
  1888. copyFeatures1(features, Constants.SAX_FEATURE_PREFIX, from, to);
  1889. }
  1890. private void copyFeatures1(
  1891. Enumeration features,
  1892. String featurePrefix,
  1893. XMLComponentManager from,
  1894. ParserConfigurationSettings to) {
  1895. while (features.hasMoreElements()) {
  1896. String featureId = featurePrefix + (String)features.nextElement();
  1897. to.addRecognizedFeatures(new String[] { featureId });
  1898. try {
  1899. to.setFeature(featureId, from.getFeature(featureId));
  1900. }
  1901. catch (XMLConfigurationException e) {
  1902. // componentManager doesn't support this feature,
  1903. // so we won't worry about it
  1904. }
  1905. }
  1906. }
  1907. private void copyFeatures1(
  1908. Enumeration features,
  1909. String featurePrefix,
  1910. XMLComponentManager from,
  1911. XMLParserConfiguration to) {
  1912. while (features.hasMoreElements()) {
  1913. String featureId = featurePrefix + (String)features.nextElement();
  1914. boolean value = from.getFeature(featureId);
  1915. try {
  1916. to.setFeature(featureId, value);
  1917. }
  1918. catch (XMLConfigurationException e) {
  1919. // componentManager doesn't support this feature,
  1920. // so we won't worry about it
  1921. }
  1922. }
  1923. }
  1924. // This is a storage class to hold information about the notations.
  1925. // We're not using XMLNotationDecl because we don't want to lose the augmentations.
  1926. protected class Notation {
  1927. public String name;
  1928. public String systemId;
  1929. public String baseURI;
  1930. public String publicId;
  1931. public Augmentations augmentations;
  1932. // equals() returns true if two Notations have the same name.
  1933. // Useful for searching Vectors for notations with the same name
  1934. public boolean equals(Object obj) {
  1935. if (obj == null) {
  1936. return false;
  1937. }
  1938. if (obj instanceof Notation) {
  1939. Notation other = (Notation)obj;
  1940. return name.equals(other.name);
  1941. }
  1942. return false;
  1943. }
  1944. // from 4.5.2
  1945. // Notation items with the same [name], [system identifier],
  1946. // [public identifier], and [declaration base URI] are considered
  1947. // to be duplicate
  1948. public boolean isDuplicate(Object obj) {
  1949. if (obj != null && obj instanceof Notation) {
  1950. Notation other = (Notation)obj;
  1951. return name.equals(other.name)
  1952. && (systemId == other.systemId
  1953. || (systemId != null && systemId.equals(other.systemId)))
  1954. && (publicId == other.publicId
  1955. || (publicId != null && publicId.equals(other.publicId)))
  1956. && (baseURI == other.baseURI
  1957. || (baseURI != null && baseURI.equals(other.baseURI)));
  1958. }
  1959. return false;
  1960. }
  1961. }
  1962. // This is a storage class to hold information about the unparsed entities.
  1963. // We're not using XMLEntityDecl because we don't want to lose the augmentations.
  1964. protected class UnparsedEntity {
  1965. public String name;
  1966. public String systemId;
  1967. public String baseURI;
  1968. public String publicId;
  1969. public String notation;
  1970. public Augmentations augmentations;
  1971. // equals() returns true if two UnparsedEntities have the same name.
  1972. // Useful for searching Vectors for entities with the same name
  1973. public boolean equals(Object obj) {
  1974. if (obj == null) {
  1975. return false;
  1976. }
  1977. if (obj instanceof UnparsedEntity) {
  1978. UnparsedEntity other = (UnparsedEntity)obj;
  1979. return name.equals(other.name);
  1980. }
  1981. return false;
  1982. }
  1983. // from 4.5.1:
  1984. // Unparsed entity items with the same [name], [system identifier],
  1985. // [public identifier], [declaration base URI], [notation name], and
  1986. // [notation] are considered to be duplicate
  1987. public boolean isDuplicate(Object obj) {
  1988. if (obj != null && obj instanceof UnparsedEntity) {
  1989. UnparsedEntity other = (UnparsedEntity)obj;
  1990. return name.equals(other.name)
  1991. && (systemId == other.systemId
  1992. || (systemId != null && systemId.equals(other.systemId)))
  1993. && (publicId == other.publicId
  1994. || (publicId != null && publicId.equals(other.publicId)))
  1995. && (baseURI == other.baseURI
  1996. || (baseURI != null && baseURI.equals(other.baseURI)))
  1997. && (notation == other.notation
  1998. || (notation != null && notation.equals(other.notation)));
  1999. }
  2000. return false;
  2001. }
  2002. }
  2003. // The following methods are used for XML Base processing
  2004. /**
  2005. * Saves the current base URI to the top of the stack.
  2006. */
  2007. protected void saveBaseURI() {
  2008. baseURIScope.push(fDepth);
  2009. baseURI.push(fCurrentBaseURI.getBaseSystemId());
  2010. literalSystemID.push(fCurrentBaseURI.getLiteralSystemId());
  2011. expandedSystemID.push(fCurrentBaseURI.getExpandedSystemId());
  2012. }
  2013. /**
  2014. * Discards the URIs at the top of the stack, and restores the ones beneath it.
  2015. */
  2016. protected void restoreBaseURI() {
  2017. baseURI.pop();
  2018. literalSystemID.pop();
  2019. expandedSystemID.pop();
  2020. baseURIScope.pop();
  2021. fCurrentBaseURI.setBaseSystemId((String)baseURI.peek());
  2022. fCurrentBaseURI.setLiteralSystemId((String)literalSystemID.peek());
  2023. fCurrentBaseURI.setExpandedSystemId((String)expandedSystemID.peek());
  2024. }
  2025. /**
  2026. * Gets the base URI that was in use at that depth
  2027. * @param depth
  2028. * @return the base URI
  2029. */
  2030. public String getBaseURI(int depth) {
  2031. int scope = scopeOf(depth);
  2032. return (String)expandedSystemID.elementAt(scope);
  2033. }
  2034. /**
  2035. * Returns a relative URI, which when resolved against the base URI at the
  2036. * specified depth, will create the current base URI.
  2037. * This is accomplished by merged the literal system IDs.
  2038. * @param depth the depth at which to start creating the relative URI
  2039. * @return a relative URI to convert the base URI at the given depth to the current
  2040. * base URI
  2041. */
  2042. public String getRelativeURI(int depth) throws MalformedURIException {
  2043. // The literal system id at the location given by "start" is *in focus* at
  2044. // the given depth. So we need to adjust it to the next scope, so that we
  2045. // only process out of focus literal system ids
  2046. int start = scopeOf(depth) + 1;
  2047. if (start == baseURIScope.size()) {
  2048. // If that is the last system id, then we don't need a relative URI
  2049. return "";
  2050. }
  2051. URI uri = new URI("file", (String)literalSystemID.elementAt(start));
  2052. for (int i = start + 1; i < baseURIScope.size(); i++) {
  2053. uri = new URI(uri, (String)literalSystemID.elementAt(i));
  2054. }
  2055. return uri.getPath();
  2056. }
  2057. // We need to find two consecutive elements in the scope stack,
  2058. // such that the first is lower than 'depth' (or equal), and the
  2059. // second is higher.
  2060. private int scopeOf(int depth) {
  2061. for (int i = baseURIScope.size() - 1; i >= 0; i--) {
  2062. if (baseURIScope.elementAt(i) <= depth)
  2063. return i;
  2064. }
  2065. // we should never get here, because 0 was put on the stack in startDocument()
  2066. return -1;
  2067. }
  2068. /**
  2069. * Search for a xml:base attribute, and if one is found, put the new base URI into
  2070. * effect.
  2071. */
  2072. protected void processXMLBaseAttributes(XMLAttributes attributes) {
  2073. String baseURIValue =
  2074. attributes.getValue(NamespaceContext.XML_URI, "base");
  2075. if (baseURIValue != null) {
  2076. try {
  2077. String expandedValue =
  2078. XMLEntityManager.expandSystemId(
  2079. baseURIValue,
  2080. fCurrentBaseURI.getExpandedSystemId(),
  2081. false);
  2082. fCurrentBaseURI.setLiteralSystemId(baseURIValue);
  2083. fCurrentBaseURI.setBaseSystemId(
  2084. fCurrentBaseURI.getExpandedSystemId());
  2085. fCurrentBaseURI.setExpandedSystemId(expandedValue);
  2086. // push the new values on the stack
  2087. saveBaseURI();
  2088. }
  2089. catch (MalformedURIException e) {
  2090. // REVISIT: throw error here
  2091. }
  2092. }
  2093. }
  2094. /**
  2095. * Set the Accept,Accept-Language,Accept-CharSet
  2096. */
  2097. protected XMLInputSource setHttpProperties(XMLInputSource source,XMLAttributes attributes) throws IOException{
  2098. String httpAcceptLang = attributes.getValue(HTTP_ACCEPT_LANGUAGE);
  2099. String httpAccept = attributes.getValue(HTTP_ACCEPT);
  2100. String httpAcceptchar = attributes.getValue(HTTP_ACCEPT_CHARSET);
  2101. if (source.getCharacterStream() == null && source.getByteStream() == null) {
  2102. XIncludeInputSource includeSource = new XIncludeInputSource(source.getPublicId(),source.getSystemId(),source.getBaseSystemId(), source.getByteStream(),source.getEncoding());
  2103. includeSource.setProperty(XINCLUDE_ATTR_ACCEPT,attributes.getValue(XINCLUDE_ATTR_ACCEPT));
  2104. includeSource.setProperty(XINCLUDE_ATTR_ACCEPT_CHARSET,attributes.getValue(XINCLUDE_ATTR_ACCEPT_CHARSET));
  2105. includeSource.setProperty(XINCLUDE_ATTR_ACCEPT_LANGUAGE,attributes.getValue(XINCLUDE_ATTR_ACCEPT_LANGUAGE));
  2106. }
  2107. return source;
  2108. }
  2109. public boolean processSchema(XPointerSchema fXPointerSchemaS,
  2110. XMLInputSource includedSource){
  2111. try{
  2112. fChildConfig = createXPointerParser();//for now -Revisit and change this.
  2113. fChildConfig.setProperty(Constants.XERCES_PROPERTY_PREFIX
  2114. + Constants.XINCLUDE_HANDLER_PROPERTY,
  2115. fXPointerSchemaS);
  2116. fXPointerSchemaS.setParent(this);
  2117. fXPointerSchemaS.setDocumentHandler(this.getDocumentHandler());
  2118. fChildConfig.parse(includedSource);
  2119. }
  2120. catch (Exception e) {
  2121. //Venu For now do this.
  2122. reportResourceError(
  2123. "XMLResourceError",
  2124. new Object[] { null, e.getMessage()});
  2125. }
  2126. return fXPointerSchemaS.isSubResourceIndentified();
  2127. }
  2128. /**
  2129. * Returns <code>true</code> if the given string
  2130. * would be valid in an HTTP header.
  2131. *
  2132. * @param value string to check
  2133. * @return <code>true</code> if the given string
  2134. * would be valid in an HTTP header
  2135. */
  2136. private boolean isValidInHTTPHeader(String value) {
  2137. char ch;
  2138. for (int i = value.length() - 1; i >= 0; --i) {
  2139. ch = value.charAt(i);
  2140. if (ch < 0x20 || ch > 0x7E) {
  2141. return false;
  2142. }
  2143. }
  2144. return true;
  2145. }
  2146. protected XMLParserConfiguration createXPointerParser(){
  2147. XMLParserConfiguration childConfig =
  2148. (XMLParserConfiguration)ObjectFactory.newInstance(
  2149. XPOINTER_DEFAULT_CONFIGURATION,
  2150. ObjectFactory.findClassLoader(),
  2151. true);
  2152. childConfig.setProperty(ERROR_REPORTER, fErrorReporter);
  2153. childConfig.setProperty(
  2154. Constants.XERCES_PROPERTY_PREFIX
  2155. + Constants.NAMESPACE_CONTEXT_PROPERTY,
  2156. fNamespaceContext);
  2157. copyFeatures(fSettings, childConfig);
  2158. return childConfig;
  2159. }
  2160. }