View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /*
6    * Copyright 2005 The Apache Software Foundation.
7    *
8    * Licensed under the Apache License, Version 2.0 (the "License");
9    * you may not use this file except in compliance with the License.
10   * You may obtain a copy of the License at
11   *
12   *      http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  
21  package com.sun.org.apache.xerces.internal.impl.xs.traversers;
22  
23  import com.sun.org.apache.xerces.internal.impl.xs.opti.SchemaDOMParser;
24  import com.sun.org.apache.xerces.internal.util.NamespaceSupport;
25  import com.sun.org.apache.xerces.internal.util.SAXLocatorWrapper;
26  import com.sun.org.apache.xerces.internal.util.SymbolTable;
27  import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl;
28  import com.sun.org.apache.xerces.internal.util.XMLSymbols;
29  import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
30  import com.sun.org.apache.xerces.internal.xni.QName;
31  import com.sun.org.apache.xerces.internal.xni.XMLString;
32  import com.sun.org.apache.xerces.internal.xni.XNIException;
33  import com.sun.org.apache.xerces.internal.xni.parser.XMLParseException;
34  import org.w3c.dom.Document;
35  import org.xml.sax.Attributes;
36  import org.xml.sax.ContentHandler;
37  import org.xml.sax.Locator;
38  import org.xml.sax.SAXException;
39  import org.xml.sax.SAXParseException;
40  import org.xml.sax.helpers.LocatorImpl;
41  
42  /**
43   * <p>SchemaContentHandler converts SAX events into XNI
44   * and passes them directly to the SchemaDOMParser.</p>
45   *
46   * @xerces.internal
47   *
48   * @author Michael Glavassevich, IBM
49   * @author Jack Z. Wang, IBM
50   *
51   */
52  final class SchemaContentHandler implements ContentHandler {
53  
54      /** Symbol table **/
55      private SymbolTable fSymbolTable;
56  
57      /** SchemaDOMParser, events will be delegated to SchemaDOMParser to pass */
58      private SchemaDOMParser fSchemaDOMParser;
59  
60      /** XML Locator wrapper for SAX. **/
61      private final SAXLocatorWrapper fSAXLocatorWrapper = new SAXLocatorWrapper();
62  
63      /** The namespace context of this document: stores namespaces in scope */
64      private NamespaceSupport fNamespaceContext = new NamespaceSupport();
65  
66      /** Indicate if push NamespaceContest is needed */
67      private boolean fNeedPushNSContext;
68  
69      /** Flag used to track whether namespace declarations are reported as attributes. */
70      private boolean fNamespacePrefixes = false;
71  
72      /** Flag used to track whether XML names and Namespace URIs have been internalized. */
73      private boolean fStringsInternalized = false;
74  
75      /** Fields for start element, end element and characters. */
76      private final QName fElementQName = new QName();
77      private final QName fAttributeQName = new QName();
78      private final XMLAttributesImpl fAttributes = new XMLAttributesImpl();
79      private final XMLString fTempString = new XMLString();
80  
81      /**
82       * <p>Constructs an SchemaContentHandler.</p>
83       */
84      public SchemaContentHandler() {}
85  
86      /*
87       * @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator)
88       */
89      public Document getDocument() {
90          return fSchemaDOMParser.getDocument();
91      }
92  
93      /*
94       * @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator)
95       */
96      public void setDocumentLocator(Locator locator) {
97          fSAXLocatorWrapper.setLocator(locator);
98      }
99  
100     /*
101      * @see org.xml.sax.ContentHandler#startDocument()
102      */
103     public void startDocument() throws SAXException {
104         fNeedPushNSContext = true;
105         try {
106             fSchemaDOMParser.startDocument(fSAXLocatorWrapper, null, fNamespaceContext, null);
107         }
108         catch (XMLParseException e) {
109             convertToSAXParseException(e);
110         }
111         catch (XNIException e) {
112             convertToSAXException(e);
113         }
114     }
115 
116     /*
117      * @see org.xml.sax.ContentHandler#endDocument()
118      */
119     public void endDocument() throws SAXException {
120         fSAXLocatorWrapper.setLocator(null);
121         try {
122             fSchemaDOMParser.endDocument(null);
123         }
124         catch (XMLParseException e) {
125             convertToSAXParseException(e);
126         }
127         catch (XNIException e) {
128             convertToSAXException(e);
129         }
130     }
131 
132     /*
133      * @see org.xml.sax.ContentHandler#startPrefixMapping(java.lang.String, java.lang.String)
134      */
135     public void startPrefixMapping(String prefix, String uri) throws SAXException {
136         if (fNeedPushNSContext) {
137             fNeedPushNSContext = false;
138             fNamespaceContext.pushContext();
139         }
140         if (!fStringsInternalized) {
141             prefix = (prefix != null) ? fSymbolTable.addSymbol(prefix) : XMLSymbols.EMPTY_STRING;
142             uri = (uri != null && uri.length() > 0) ? fSymbolTable.addSymbol(uri) : null;
143         }
144         else {
145             if (prefix == null) {
146                 prefix = XMLSymbols.EMPTY_STRING;
147             }
148             if (uri != null && uri.length() == 0) {
149                 uri = null;
150             }
151         }
152         fNamespaceContext.declarePrefix(prefix, uri);
153     }
154 
155     /*
156      * @see org.xml.sax.ContentHandler#endPrefixMapping(java.lang.String)
157      */
158     public void endPrefixMapping(String prefix) throws SAXException {
159         // do nothing
160     }
161 
162     /*
163      * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
164      */
165     public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
166         if (fNeedPushNSContext) {
167             fNamespaceContext.pushContext();
168         }
169         fNeedPushNSContext = true;
170 
171         // Fill element QName and XMLAttributes
172         fillQName(fElementQName, uri, localName, qName);
173         fillXMLAttributes(atts);
174 
175         // Add namespace declarations if necessary
176         if (!fNamespacePrefixes) {
177             final int prefixCount = fNamespaceContext.getDeclaredPrefixCount();
178             if (prefixCount > 0) {
179                 addNamespaceDeclarations(prefixCount);
180             }
181         }
182 
183         try {
184             fSchemaDOMParser.startElement(fElementQName, fAttributes, null);
185         }
186         catch (XMLParseException e) {
187             convertToSAXParseException(e);
188         }
189         catch (XNIException e) {
190             convertToSAXException(e);
191         }
192     }
193 
194     /*
195      * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
196      */
197     public void endElement(String uri, String localName, String qName) throws SAXException {
198         fillQName(fElementQName, uri, localName, qName);
199         try {
200             fSchemaDOMParser.endElement(fElementQName, null);
201         }
202         catch (XMLParseException e) {
203             convertToSAXParseException(e);
204         }
205         catch (XNIException e) {
206             convertToSAXException(e);
207         }
208         finally {
209             fNamespaceContext.popContext();
210         }
211     }
212 
213     /*
214      * @see org.xml.sax.ContentHandler#characters(char[], int, int)
215      */
216     public void characters(char[] ch, int start, int length) throws SAXException {
217         try {
218             fTempString.setValues(ch, start, length);
219             fSchemaDOMParser.characters(fTempString, null);
220         }
221         catch (XMLParseException e) {
222             convertToSAXParseException(e);
223         }
224         catch (XNIException e) {
225             convertToSAXException(e);
226         }
227     }
228 
229     /*
230      * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
231      */
232     public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
233         try {
234             fTempString.setValues(ch, start, length);
235             fSchemaDOMParser.ignorableWhitespace(fTempString, null);
236         }
237         catch (XMLParseException e) {
238             convertToSAXParseException(e);
239         }
240         catch (XNIException e) {
241             convertToSAXException(e);
242         }
243     }
244 
245     /*
246      * @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String, java.lang.String)
247      */
248     public void processingInstruction(String target, String data) throws SAXException {
249         try {
250             fTempString.setValues(data.toCharArray(), 0, data.length());
251             fSchemaDOMParser.processingInstruction(target, fTempString, null);
252         }
253         catch (XMLParseException e) {
254             convertToSAXParseException(e);
255         }
256         catch (XNIException e) {
257             convertToSAXException(e);
258         }
259     }
260 
261     /*
262      * @see org.xml.sax.ContentHandler#skippedEntity(java.lang.String)
263      */
264     public void skippedEntity(String arg) throws SAXException {
265         // do-nothing
266     }
267 
268     /*
269      * Other methods
270      */
271 
272     private void fillQName(QName toFill, String uri, String localpart, String rawname) {
273         if (!fStringsInternalized) {
274             uri = (uri != null && uri.length() > 0) ? fSymbolTable.addSymbol(uri) : null;
275             localpart = (localpart != null) ? fSymbolTable.addSymbol(localpart) : XMLSymbols.EMPTY_STRING;
276             rawname = (rawname != null) ? fSymbolTable.addSymbol(rawname) : XMLSymbols.EMPTY_STRING;
277         }
278         else {
279             if (uri != null && uri.length() == 0) {
280                 uri = null;
281             }
282             if (localpart == null) {
283                 localpart = XMLSymbols.EMPTY_STRING;
284             }
285             if (rawname == null) {
286                 rawname = XMLSymbols.EMPTY_STRING;
287             }
288         }
289         String prefix = XMLSymbols.EMPTY_STRING;
290         int prefixIdx = rawname.indexOf(':');
291         if (prefixIdx != -1) {
292             prefix = fSymbolTable.addSymbol(rawname.substring(0, prefixIdx));
293             // local part may be an empty string if this is a namespace declaration
294             if (localpart == XMLSymbols.EMPTY_STRING) {
295                 localpart = fSymbolTable.addSymbol(rawname.substring(prefixIdx + 1));
296             }
297         }
298         // local part may be an empty string if this is a namespace declaration
299         else if (localpart == XMLSymbols.EMPTY_STRING) {
300             localpart = rawname;
301         }
302         toFill.setValues(prefix, localpart, rawname, uri);
303     }
304 
305     private void fillXMLAttributes(Attributes atts) {
306         fAttributes.removeAllAttributes();
307         final int attrCount = atts.getLength();
308         for (int i = 0; i < attrCount; ++i) {
309             fillQName(fAttributeQName, atts.getURI(i), atts.getLocalName(i), atts.getQName(i));
310             String type = atts.getType(i);
311             fAttributes.addAttributeNS(fAttributeQName, (type != null) ? type : XMLSymbols.fCDATASymbol, atts.getValue(i));
312             fAttributes.setSpecified(i, true);
313         }
314     }
315 
316     private void addNamespaceDeclarations(final int prefixCount) {
317         String prefix = null;
318         String localpart = null;
319         String rawname = null;
320         String nsPrefix = null;
321         String nsURI = null;
322         for (int i = 0; i < prefixCount; ++i) {
323             nsPrefix = fNamespaceContext.getDeclaredPrefixAt(i);
324             nsURI = fNamespaceContext.getURI(nsPrefix);
325             if (nsPrefix.length() > 0) {
326                 prefix = XMLSymbols.PREFIX_XMLNS;
327                 localpart = nsPrefix;
328                 rawname = fSymbolTable.addSymbol(prefix + ":" + localpart);
329             }
330             else {
331                 prefix = XMLSymbols.EMPTY_STRING;
332                 localpart = XMLSymbols.PREFIX_XMLNS;
333                 rawname = XMLSymbols.PREFIX_XMLNS;
334             }
335             fAttributeQName.setValues(prefix, localpart, rawname, NamespaceContext.XMLNS_URI);
336             fAttributes.addAttribute(fAttributeQName, XMLSymbols.fCDATASymbol, nsURI);
337         }
338     }
339 
340     public void reset(SchemaDOMParser schemaDOMParser, SymbolTable symbolTable,
341             boolean namespacePrefixes, boolean stringsInternalized) {
342         fSchemaDOMParser = schemaDOMParser;
343         fSymbolTable = symbolTable;
344         fNamespacePrefixes = namespacePrefixes;
345         fStringsInternalized = stringsInternalized;
346     }
347 
348     /*
349      * Static methods
350      */
351 
352     static void convertToSAXParseException(XMLParseException e) throws SAXException {
353         Exception ex = e.getException();
354         if (ex == null) {
355             // must be a parser exception; mine it for locator info and throw
356             // a SAXParseException
357             LocatorImpl locatorImpl = new LocatorImpl();
358             locatorImpl.setPublicId(e.getPublicId());
359             locatorImpl.setSystemId(e.getExpandedSystemId());
360             locatorImpl.setLineNumber(e.getLineNumber());
361             locatorImpl.setColumnNumber(e.getColumnNumber());
362             throw new SAXParseException(e.getMessage(), locatorImpl);
363         }
364         if (ex instanceof SAXException) {
365             // why did we create an XMLParseException?
366             throw (SAXException) ex;
367         }
368         throw new SAXException(ex);
369     }
370 
371     static void convertToSAXException(XNIException e) throws SAXException {
372         Exception ex = e.getException();
373         if (ex == null) {
374             throw new SAXException(e.getMessage());
375         }
376         if (ex instanceof SAXException) {
377             throw (SAXException) ex;
378         }
379         throw new SAXException(ex);
380     }
381 
382 } // SchemaContentHandler