1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 2001-2003 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.impl.xs.opti;
  58. import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter;
  59. import com.sun.org.apache.xerces.internal.impl.xs.SchemaSymbols;
  60. import com.sun.org.apache.xerces.internal.impl.xs.XSMessageFormatter;
  61. import com.sun.org.apache.xerces.internal.util.XMLChar;
  62. import com.sun.org.apache.xerces.internal.xni.Augmentations;
  63. import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
  64. import com.sun.org.apache.xerces.internal.xni.QName;
  65. import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
  66. import com.sun.org.apache.xerces.internal.xni.XMLLocator;
  67. import com.sun.org.apache.xerces.internal.xni.XMLString;
  68. import com.sun.org.apache.xerces.internal.xni.XNIException;
  69. import org.w3c.dom.Document;
  70. /**
  71. * {@link XMLDocumentHandler} that
  72. * builds DOM representation for XML Schema documents.
  73. *
  74. * <p>
  75. * TODO: this class should be better renamed to
  76. * SchemaDOMBuilder since this class is not a "parser", which is used
  77. * to imply software that reads raw Unicode and angle brackets.
  78. *
  79. * @author Rahul Srivastava, Sun Microsystems Inc.
  80. * @author Sandy Gao, IBM
  81. *
  82. * @version $Id: SchemaDOMParser.java,v 1.8 2004/04/30 02:42:43 mrglavas Exp $
  83. */
  84. public class SchemaDOMParser extends DefaultXMLDocumentHandler {
  85. //
  86. // Data
  87. //
  88. // the locator containing line/column information
  89. protected XMLLocator fLocator;
  90. // namespace context, needed for producing
  91. // representations of annotations
  92. protected NamespaceContext fNamespaceContext = null;
  93. SchemaDOM schemaDOM;
  94. //
  95. // Constructors
  96. //
  97. public SchemaDOMParser(XMLErrorReporter errorReporter) {
  98. fErrorReporter = errorReporter;
  99. }
  100. // where an annotation element itself begins
  101. // -1 means not in an annotation's scope
  102. private int fAnnotationDepth = -1;
  103. // Where xs:appinfo or xs:documentation starts;
  104. // -1 means not in the scope of either of the two elements.
  105. private int fInnerAnnotationDepth = -1;
  106. // The current element depth
  107. private int fDepth = -1;
  108. // Use to report the error when characters are not allowed.
  109. XMLErrorReporter fErrorReporter;
  110. //
  111. // XMLDocumentHandler methods
  112. //
  113. public void startDocument(XMLLocator locator, String encoding,
  114. NamespaceContext namespaceContext, Augmentations augs)
  115. throws XNIException {
  116. schemaDOM = new SchemaDOM();
  117. fAnnotationDepth = -1;
  118. fInnerAnnotationDepth = -1;
  119. fDepth = -1;
  120. fLocator = locator;
  121. fNamespaceContext = namespaceContext;
  122. } // startDocument(XMLLocator,String,NamespaceContext, Augmentations)
  123. /**
  124. * The end of the document.
  125. * @param augs Additional information that may include infoset augmentations
  126. *
  127. * @throws XNIException Thrown by handler to signal an error.
  128. */
  129. public void endDocument(Augmentations augs) throws XNIException {
  130. // To debug the DOM created uncomment the line below
  131. // schemaDOM.printDOM();
  132. } // endDocument()
  133. /**
  134. * A comment.
  135. *
  136. * @param text The text in the comment.
  137. * @param augs Additional information that may include infoset augmentations
  138. *
  139. * @exception XNIException
  140. * Thrown by application to signal an error.
  141. */
  142. public void comment(XMLString text, Augmentations augs) throws XNIException {
  143. if(fAnnotationDepth > -1) {
  144. schemaDOM.comment(text);
  145. }
  146. }
  147. /**
  148. * A processing instruction. Processing instructions consist of a
  149. * target name and, optionally, text data. The data is only meaningful
  150. * to the application.
  151. * <p>
  152. * Typically, a processing instruction's data will contain a series
  153. * of pseudo-attributes. These pseudo-attributes follow the form of
  154. * element attributes but are <strong>not</strong> parsed or presented
  155. * to the application as anything other than text. The application is
  156. * responsible for parsing the data.
  157. *
  158. * @param target The target.
  159. * @param data The data or null if none specified.
  160. * @param augs Additional information that may include infoset augmentations
  161. *
  162. * @exception XNIException
  163. * Thrown by handler to signal an error.
  164. */
  165. public void processingInstruction(String target, XMLString data, Augmentations augs)
  166. throws XNIException {
  167. if(fAnnotationDepth > -1) {
  168. schemaDOM.processingInstruction(target, data.toString());
  169. }
  170. }
  171. /**
  172. * Character content.
  173. *
  174. * @param text The content.
  175. * @param augs Additional information that may include infoset augmentations
  176. *
  177. * @exception XNIException
  178. * Thrown by handler to signal an error.
  179. */
  180. public void characters(XMLString text, Augmentations augs) throws XNIException {
  181. // when it's not within xs:appinfo or xs:documentation
  182. if (fInnerAnnotationDepth == -1 ) {
  183. for (int i=text.offset; i<text.offset+text.length; i++) {
  184. // and there is a non-whitespace character
  185. if (!XMLChar.isSpace(text.ch[i])) {
  186. // the string we saw: starting from the first non-whitespace character.
  187. String txt = new String(text.ch, i, text.length+text.offset-i);
  188. // report an error
  189. fErrorReporter.reportError(XSMessageFormatter.SCHEMA_DOMAIN,
  190. "s4s-elt-character",
  191. new Object[]{txt},
  192. XMLErrorReporter.SEVERITY_ERROR);
  193. break;
  194. }
  195. }
  196. // don't call super.characters() when it's not within one of the 2
  197. // annotation elements: the traversers ignore them anyway. We can
  198. // save time/memory creating the text nodes.
  199. }
  200. // when it's within either of the 2 elements, characters are allowed
  201. // and we need to store them.
  202. else {
  203. schemaDOM.characters(text);
  204. }
  205. }
  206. /**
  207. * The start of an element.
  208. *
  209. * @param element The name of the element.
  210. * @param attributes The element attributes.
  211. * @param augs Additional information that may include infoset augmentations
  212. *
  213. * @exception XNIException
  214. * Thrown by handler to signal an error.
  215. */
  216. public void startElement(QName element, XMLAttributes attributes, Augmentations augs)
  217. throws XNIException {
  218. fDepth++;
  219. // while it is true that non-whitespace character data
  220. // may only occur in appInfo or documentation
  221. // elements, it's certainly legal for comments and PI's to
  222. // occur as children of annotation; we need
  223. // to account for these here.
  224. if (fAnnotationDepth == -1) {
  225. if (element.uri == SchemaSymbols.URI_SCHEMAFORSCHEMA &&
  226. element.localpart == SchemaSymbols.ELT_ANNOTATION) {
  227. fAnnotationDepth = fDepth;
  228. schemaDOM.startAnnotation(element, attributes, fNamespaceContext);
  229. }
  230. } else if(fDepth == fAnnotationDepth+1) {
  231. fInnerAnnotationDepth = fDepth;
  232. schemaDOM.startAnnotationElement(element, attributes);
  233. } else {
  234. schemaDOM.startAnnotationElement(element, attributes);
  235. // avoid falling through; don't call startElement in this case
  236. return;
  237. }
  238. schemaDOM.startElement(element, attributes,
  239. fLocator.getLineNumber(),
  240. fLocator.getColumnNumber());
  241. }
  242. /**
  243. * An empty element.
  244. *
  245. * @param element The name of the element.
  246. * @param attributes The element attributes.
  247. * @param augs Additional information that may include infoset augmentations
  248. *
  249. * @exception XNIException
  250. * Thrown by handler to signal an error.
  251. */
  252. public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs)
  253. throws XNIException {
  254. // the order of events that occurs here is:
  255. // schemaDOM.startAnnotation/startAnnotationElement (if applicable)
  256. // schemaDOM.emptyElement (basically the same as startElement then endElement)
  257. // schemaDOM.endAnnotationElement (if applicable)
  258. // the order of events that would occur if this was <element></element>:
  259. // schemaDOM.startAnnotation/startAnnotationElement (if applicable)
  260. // schemaDOM.startElement
  261. // schemaDOM.endAnnotationElement (if applicable)
  262. // schemaDOM.endElementElement
  263. // Thus, we can see that the order of events isn't the same. However, it doesn't
  264. // seem to matter. -- PJM
  265. if (fAnnotationDepth == -1) {
  266. // this is messed up, but a case to consider:
  267. if (element.uri == SchemaSymbols.URI_SCHEMAFORSCHEMA &&
  268. element.localpart == SchemaSymbols.ELT_ANNOTATION) {
  269. schemaDOM.startAnnotation(element, attributes, fNamespaceContext);
  270. }
  271. } else {
  272. schemaDOM.startAnnotationElement(element, attributes);
  273. }
  274. schemaDOM.emptyElement(element, attributes,
  275. fLocator.getLineNumber(),
  276. fLocator.getColumnNumber());
  277. if (fAnnotationDepth == -1) {
  278. // this is messed up, but a case to consider:
  279. if (element.uri == SchemaSymbols.URI_SCHEMAFORSCHEMA &&
  280. element.localpart == SchemaSymbols.ELT_ANNOTATION) {
  281. schemaDOM.endAnnotationElement(element, true);
  282. }
  283. } else {
  284. schemaDOM.endAnnotationElement(element, false);
  285. }
  286. }
  287. /**
  288. * The end of an element.
  289. *
  290. * @param element The name of the element.
  291. * @param augs Additional information that may include infoset augmentations
  292. *
  293. * @exception XNIException
  294. * Thrown by handler to signal an error.
  295. */
  296. public void endElement(QName element, Augmentations augs) throws XNIException {
  297. // when we reach the endElement of xs:appinfo or xs:documentation,
  298. // change fInnerAnnotationDepth to -1
  299. if(fAnnotationDepth > -1) {
  300. if (fInnerAnnotationDepth == fDepth) {
  301. fInnerAnnotationDepth = -1;
  302. schemaDOM.endAnnotationElement(element, false);
  303. schemaDOM.endElement();
  304. } else if (fAnnotationDepth == fDepth) {
  305. fAnnotationDepth = -1;
  306. schemaDOM.endAnnotationElement(element, true);
  307. schemaDOM.endElement();
  308. } else { // inside a child of annotation
  309. schemaDOM.endAnnotationElement(element, false);
  310. }
  311. } else { // not in an annotation at all
  312. schemaDOM.endElement();
  313. }
  314. fDepth--;
  315. }
  316. /**
  317. * Ignorable whitespace. For this method to be called, the document
  318. * source must have some way of determining that the text containing
  319. * only whitespace characters should be considered ignorable. For
  320. * example, the validator can determine if a length of whitespace
  321. * characters in the document are ignorable based on the element
  322. * content model.
  323. *
  324. * @param text The ignorable whitespace.
  325. * @param augs Additional information that may include infoset augmentations
  326. *
  327. * @exception XNIException
  328. * Thrown by handler to signal an error.
  329. */
  330. public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException {
  331. // unlikely to be called, but you never know...
  332. if (fAnnotationDepth != -1 ) {
  333. schemaDOM.characters(text);
  334. }
  335. }
  336. /**
  337. * The start of a CDATA section.
  338. *
  339. * @param augs Additional information that may include infoset augmentations
  340. *
  341. * @exception XNIException
  342. * Thrown by handler to signal an error.
  343. */
  344. public void startCDATA(Augmentations augs) throws XNIException {
  345. // only deal with CDATA boundaries within an annotation.
  346. if (fAnnotationDepth != -1) {
  347. schemaDOM.startAnnotationCDATA();
  348. }
  349. }
  350. /**
  351. * The end of a CDATA section.
  352. *
  353. * @param augs Additional information that may include infoset augmentations
  354. *
  355. * @exception XNIException
  356. * Thrown by handler to signal an error.
  357. */
  358. public void endCDATA(Augmentations augs) throws XNIException {
  359. // only deal with CDATA boundaries within an annotation.
  360. if (fAnnotationDepth != -1) {
  361. schemaDOM.endAnnotationCDATA();
  362. }
  363. }
  364. //
  365. // other methods
  366. //
  367. /**
  368. * Returns the DOM document object.
  369. */
  370. public Document getDocument() {
  371. return schemaDOM;
  372. }
  373. }