001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.xerces.impl.xs.traversers;
019:
020: import org.apache.xerces.impl.xs.opti.SchemaDOMParser;
021: import org.apache.xerces.util.NamespaceSupport;
022: import org.apache.xerces.util.SAXLocatorWrapper;
023: import org.apache.xerces.util.SymbolTable;
024: import org.apache.xerces.util.XMLAttributesImpl;
025: import org.apache.xerces.util.XMLStringBuffer;
026: import org.apache.xerces.util.XMLSymbols;
027: import org.apache.xerces.xni.NamespaceContext;
028: import org.apache.xerces.xni.QName;
029: import org.apache.xerces.xni.XMLString;
030: import org.apache.xerces.xni.XNIException;
031: import org.apache.xerces.xni.parser.XMLParseException;
032: import org.w3c.dom.Document;
033: import org.xml.sax.Attributes;
034: import org.xml.sax.ContentHandler;
035: import org.xml.sax.Locator;
036: import org.xml.sax.SAXException;
037: import org.xml.sax.SAXParseException;
038: import org.xml.sax.helpers.LocatorImpl;
039:
040: /**
041: * <p>SchemaContentHandler converts SAX events into XNI
042: * and passes them directly to the SchemaDOMParser.</p>
043: *
044: * @xerces.internal
045: *
046: * @author Michael Glavassevich, IBM
047: * @author Jack Z. Wang, IBM
048: *
049: * @version $Id: SchemaContentHandler.java 450980 2006-09-28 19:37:19Z mrglavas $
050: */
051: final class SchemaContentHandler implements ContentHandler {
052:
053: /** Symbol table **/
054: private SymbolTable fSymbolTable;
055:
056: /** SchemaDOMParser, events will be delegated to SchemaDOMParser to pass */
057: private SchemaDOMParser fSchemaDOMParser;
058:
059: /** XML Locator wrapper for SAX. **/
060: private final SAXLocatorWrapper fSAXLocatorWrapper = new SAXLocatorWrapper();
061:
062: /** The namespace context of this document: stores namespaces in scope */
063: private NamespaceSupport fNamespaceContext = new NamespaceSupport();
064:
065: /** Indicate if push NamespaceContest is needed */
066: private boolean fNeedPushNSContext;
067:
068: /** Flag used to track whether namespace declarations are reported as attributes. */
069: private boolean fNamespacePrefixes = false;
070:
071: /** Flag used to track whether XML names and Namespace URIs have been internalized. */
072: private boolean fStringsInternalized = false;
073:
074: /** Fields for start element, end element and characters. */
075: private final QName fElementQName = new QName();
076: private final QName fAttributeQName = new QName();
077: private final XMLAttributesImpl fAttributes = new XMLAttributesImpl();
078: private final XMLString fTempString = new XMLString();
079: private final XMLStringBuffer fStringBuffer = new XMLStringBuffer();
080:
081: /**
082: * <p>Constructs an SchemaContentHandler.</p>
083: */
084: public SchemaContentHandler() {
085: }
086:
087: /*
088: * @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator)
089: */
090: public Document getDocument() {
091: return fSchemaDOMParser.getDocument();
092: }
093:
094: /*
095: * @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator)
096: */
097: public void setDocumentLocator(Locator locator) {
098: fSAXLocatorWrapper.setLocator(locator);
099: }
100:
101: /*
102: * @see org.xml.sax.ContentHandler#startDocument()
103: */
104: public void startDocument() throws SAXException {
105: fNeedPushNSContext = true;
106: try {
107: fSchemaDOMParser.startDocument(fSAXLocatorWrapper, null,
108: fNamespaceContext, null);
109: } catch (XMLParseException e) {
110: convertToSAXParseException(e);
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: } catch (XMLParseException e) {
124: convertToSAXParseException(e);
125: } catch (XNIException e) {
126: convertToSAXException(e);
127: }
128: }
129:
130: /*
131: * @see org.xml.sax.ContentHandler#startPrefixMapping(java.lang.String, java.lang.String)
132: */
133: public void startPrefixMapping(String prefix, String uri)
134: throws SAXException {
135: if (fNeedPushNSContext) {
136: fNeedPushNSContext = false;
137: fNamespaceContext.pushContext();
138: }
139: if (!fStringsInternalized) {
140: prefix = (prefix != null) ? fSymbolTable.addSymbol(prefix)
141: : XMLSymbols.EMPTY_STRING;
142: uri = (uri != null && uri.length() > 0) ? fSymbolTable
143: .addSymbol(uri) : null;
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,
166: String qName, Attributes atts) throws SAXException {
167: if (fNeedPushNSContext) {
168: fNamespaceContext.pushContext();
169: }
170: fNeedPushNSContext = true;
171:
172: // Fill element QName and XMLAttributes
173: fillQName(fElementQName, uri, localName, qName);
174: fillXMLAttributes(atts);
175:
176: // Add namespace declarations if necessary
177: if (!fNamespacePrefixes) {
178: final int prefixCount = fNamespaceContext
179: .getDeclaredPrefixCount();
180: if (prefixCount > 0) {
181: addNamespaceDeclarations(prefixCount);
182: }
183: }
184:
185: try {
186: fSchemaDOMParser.startElement(fElementQName, fAttributes,
187: null);
188: } catch (XMLParseException e) {
189: convertToSAXParseException(e);
190: } catch (XNIException e) {
191: convertToSAXException(e);
192: }
193: }
194:
195: /*
196: * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
197: */
198: public void endElement(String uri, String localName, String qName)
199: throws SAXException {
200: fillQName(fElementQName, uri, localName, qName);
201: try {
202: fSchemaDOMParser.endElement(fElementQName, null);
203: } catch (XMLParseException e) {
204: convertToSAXParseException(e);
205: } catch (XNIException e) {
206: convertToSAXException(e);
207: } finally {
208: fNamespaceContext.popContext();
209: }
210: }
211:
212: /*
213: * @see org.xml.sax.ContentHandler#characters(char[], int, int)
214: */
215: public void characters(char[] ch, int start, int length)
216: throws SAXException {
217: try {
218: fTempString.setValues(ch, start, length);
219: fSchemaDOMParser.characters(fTempString, null);
220: } catch (XMLParseException e) {
221: convertToSAXParseException(e);
222: } catch (XNIException e) {
223: convertToSAXException(e);
224: }
225: }
226:
227: /*
228: * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
229: */
230: public void ignorableWhitespace(char[] ch, int start, int length)
231: throws SAXException {
232: try {
233: fTempString.setValues(ch, start, length);
234: fSchemaDOMParser.ignorableWhitespace(fTempString, null);
235: } catch (XMLParseException e) {
236: convertToSAXParseException(e);
237: } catch (XNIException e) {
238: convertToSAXException(e);
239: }
240: }
241:
242: /*
243: * @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String, java.lang.String)
244: */
245: public void processingInstruction(String target, String data)
246: throws SAXException {
247: try {
248: fTempString.setValues(data.toCharArray(), 0, data.length());
249: fSchemaDOMParser.processingInstruction(target, fTempString,
250: null);
251: } catch (XMLParseException e) {
252: convertToSAXParseException(e);
253: } catch (XNIException e) {
254: convertToSAXException(e);
255: }
256: }
257:
258: /*
259: * @see org.xml.sax.ContentHandler#skippedEntity(java.lang.String)
260: */
261: public void skippedEntity(String arg) throws SAXException {
262: // do-nothing
263: }
264:
265: /*
266: * Other methods
267: */
268:
269: private void fillQName(QName toFill, String uri, String localpart,
270: String rawname) {
271: if (!fStringsInternalized) {
272: uri = (uri != null && uri.length() > 0) ? fSymbolTable
273: .addSymbol(uri) : null;
274: localpart = (localpart != null) ? fSymbolTable
275: .addSymbol(localpart) : XMLSymbols.EMPTY_STRING;
276: rawname = (rawname != null) ? fSymbolTable
277: .addSymbol(rawname) : XMLSymbols.EMPTY_STRING;
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,
293: prefixIdx));
294: // local part may be an empty string if this is a namespace declaration
295: if (localpart == XMLSymbols.EMPTY_STRING) {
296: localpart = fSymbolTable.addSymbol(rawname
297: .substring(prefixIdx + 1));
298: }
299: }
300: // local part may be an empty string if this is a namespace declaration
301: else if (localpart == XMLSymbols.EMPTY_STRING) {
302: localpart = rawname;
303: }
304: toFill.setValues(prefix, localpart, rawname, uri);
305: }
306:
307: private void fillXMLAttributes(Attributes atts) {
308: fAttributes.removeAllAttributes();
309: final int attrCount = atts.getLength();
310: for (int i = 0; i < attrCount; ++i) {
311: fillQName(fAttributeQName, atts.getURI(i), atts
312: .getLocalName(i), atts.getQName(i));
313: String type = atts.getType(i);
314: fAttributes.addAttributeNS(fAttributeQName,
315: (type != null) ? type : XMLSymbols.fCDATASymbol,
316: atts.getValue(i));
317: fAttributes.setSpecified(i, true);
318: }
319: }
320:
321: private void addNamespaceDeclarations(final int prefixCount) {
322: String prefix = null;
323: String localpart = null;
324: String rawname = null;
325: String nsPrefix = null;
326: String nsURI = null;
327: for (int i = 0; i < prefixCount; ++i) {
328: nsPrefix = fNamespaceContext.getDeclaredPrefixAt(i);
329: nsURI = fNamespaceContext.getURI(nsPrefix);
330: if (nsPrefix.length() > 0) {
331: prefix = XMLSymbols.PREFIX_XMLNS;
332: localpart = nsPrefix;
333: fStringBuffer.clear();
334: fStringBuffer.append(prefix);
335: fStringBuffer.append(':');
336: fStringBuffer.append(localpart);
337: rawname = fSymbolTable.addSymbol(fStringBuffer.ch,
338: fStringBuffer.offset, fStringBuffer.length);
339: } else {
340: prefix = XMLSymbols.EMPTY_STRING;
341: localpart = XMLSymbols.PREFIX_XMLNS;
342: rawname = XMLSymbols.PREFIX_XMLNS;
343: }
344: fAttributeQName.setValues(prefix, localpart, rawname,
345: NamespaceContext.XMLNS_URI);
346: fAttributes.addAttribute(fAttributeQName,
347: XMLSymbols.fCDATASymbol, nsURI);
348: }
349: }
350:
351: public void reset(SchemaDOMParser schemaDOMParser,
352: SymbolTable symbolTable, boolean namespacePrefixes,
353: boolean stringsInternalized) {
354: fSchemaDOMParser = schemaDOMParser;
355: fSymbolTable = symbolTable;
356: fNamespacePrefixes = namespacePrefixes;
357: fStringsInternalized = stringsInternalized;
358: }
359:
360: /*
361: * Static methods
362: */
363:
364: static void convertToSAXParseException(XMLParseException e)
365: throws SAXException {
366: Exception ex = e.getException();
367: if (ex == null) {
368: // must be a parser exception; mine it for locator info and throw
369: // a SAXParseException
370: LocatorImpl locatorImpl = new LocatorImpl();
371: locatorImpl.setPublicId(e.getPublicId());
372: locatorImpl.setSystemId(e.getExpandedSystemId());
373: locatorImpl.setLineNumber(e.getLineNumber());
374: locatorImpl.setColumnNumber(e.getColumnNumber());
375: throw new SAXParseException(e.getMessage(), locatorImpl);
376: }
377: if (ex instanceof SAXException) {
378: // why did we create an XMLParseException?
379: throw (SAXException) ex;
380: }
381: throw new SAXException(ex);
382: }
383:
384: static void convertToSAXException(XNIException e)
385: throws SAXException {
386: Exception ex = e.getException();
387: if (ex == null) {
388: throw new SAXException(e.getMessage());
389: }
390: if (ex instanceof SAXException) {
391: throw (SAXException) ex;
392: }
393: throw new SAXException(ex);
394: }
395:
396: } // SchemaContentHandler
|