1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 /* 6 * Licensed to the Apache Software Foundation (ASF) under one or more 7 * contributor license agreements. See the NOTICE file distributed with 8 * this work for additional information regarding copyright ownership. 9 * The ASF licenses this file to You under the Apache License, Version 2.0 10 * (the "License"); you may not use this file except in compliance with 11 * the License. You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 */ 21 22 package com.sun.org.apache.xerces.internal.impl.xs.traversers; 23 24 import java.util.ArrayList; 25 import java.util.Iterator; 26 27 import javax.xml.stream.XMLEventReader; 28 import javax.xml.stream.XMLStreamConstants; 29 import javax.xml.stream.XMLStreamException; 30 import javax.xml.stream.XMLStreamReader; 31 import javax.xml.stream.events.Attribute; 32 import javax.xml.stream.events.EndElement; 33 import javax.xml.stream.events.Namespace; 34 import javax.xml.stream.events.ProcessingInstruction; 35 import javax.xml.stream.events.StartElement; 36 import javax.xml.stream.events.XMLEvent; 37 38 import com.sun.org.apache.xerces.internal.impl.xs.opti.SchemaDOMParser; 39 import com.sun.org.apache.xerces.internal.util.JAXPNamespaceContextWrapper; 40 import com.sun.org.apache.xerces.internal.util.StAXLocationWrapper; 41 import com.sun.org.apache.xerces.internal.util.SymbolTable; 42 import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl; 43 import com.sun.org.apache.xerces.internal.util.XMLStringBuffer; 44 import com.sun.org.apache.xerces.internal.util.XMLSymbols; 45 import com.sun.org.apache.xerces.internal.xni.NamespaceContext; 46 import com.sun.org.apache.xerces.internal.xni.QName; 47 import com.sun.org.apache.xerces.internal.xni.XMLString; 48 import com.sun.org.apache.xerces.internal.xni.XNIException; 49 import org.w3c.dom.Document; 50 51 /** 52 * <p>StAXSchemaParser reads StAX events, converts them into XNI events 53 * and passes them directly to the SchemaDOMParser.</p> 54 * 55 * @xerces.internal 56 * 57 * @version $Id: StAXSchemaParser.java,v 1.2 2010-10-26 23:01:12 joehw Exp $ 58 */ 59 final class StAXSchemaParser { 60 61 /** Chunk size (1024). */ 62 private static final int CHUNK_SIZE = (1 << 10); 63 64 /** Chunk mask (CHUNK_SIZE - 1). */ 65 private static final int CHUNK_MASK = CHUNK_SIZE - 1; 66 67 /** Array for holding character data. **/ 68 private final char [] fCharBuffer = new char[CHUNK_SIZE]; 69 70 /** Symbol table **/ 71 private SymbolTable fSymbolTable; 72 73 /** SchemaDOMParser, events will be delegated to SchemaDOMParser to pass */ 74 private SchemaDOMParser fSchemaDOMParser; 75 76 /** XML Locator wrapper for SAX. **/ 77 private final StAXLocationWrapper fLocationWrapper = new StAXLocationWrapper(); 78 79 /** The namespace context of this document: stores namespaces in scope */ 80 private final JAXPNamespaceContextWrapper fNamespaceContext = new JAXPNamespaceContextWrapper(fSymbolTable); 81 82 /** Fields for start element, end element and characters. */ 83 private final QName fElementQName = new QName(); 84 private final QName fAttributeQName = new QName(); 85 private final XMLAttributesImpl fAttributes = new XMLAttributesImpl(); 86 private final XMLString fTempString = new XMLString(); 87 private final ArrayList fDeclaredPrefixes = new ArrayList(); 88 private final XMLStringBuffer fStringBuffer = new XMLStringBuffer(); 89 private int fDepth; 90 91 public StAXSchemaParser() { 92 fNamespaceContext.setDeclaredPrefixes(fDeclaredPrefixes); 93 } 94 95 public void reset(SchemaDOMParser schemaDOMParser, SymbolTable symbolTable) { 96 fSchemaDOMParser = schemaDOMParser; 97 fSymbolTable = symbolTable; 98 fNamespaceContext.setSymbolTable(fSymbolTable); 99 fNamespaceContext.reset(); 100 } 101 102 public Document getDocument() { 103 return fSchemaDOMParser.getDocument(); 104 } 105 106 public void parse(XMLEventReader input) throws XMLStreamException, XNIException { 107 XMLEvent currentEvent = input.peek(); 108 if (currentEvent != null) { 109 int eventType = currentEvent.getEventType(); 110 if (eventType != XMLStreamConstants.START_DOCUMENT && 111 eventType != XMLStreamConstants.START_ELEMENT) { 112 throw new XMLStreamException(); 113 } 114 fLocationWrapper.setLocation(currentEvent.getLocation()); 115 fSchemaDOMParser.startDocument(fLocationWrapper, null, fNamespaceContext, null); 116 loop: while (input.hasNext()) { 117 currentEvent = input.nextEvent(); 118 eventType = currentEvent.getEventType(); 119 switch (eventType) { 120 case XMLStreamConstants.START_ELEMENT: 121 ++fDepth; 122 StartElement start = currentEvent.asStartElement(); 123 fillQName(fElementQName, start.getName()); 124 fLocationWrapper.setLocation(start.getLocation()); 125 fNamespaceContext.setNamespaceContext(start.getNamespaceContext()); 126 fillXMLAttributes(start); 127 fillDeclaredPrefixes(start); 128 addNamespaceDeclarations(); 129 fNamespaceContext.pushContext(); 130 fSchemaDOMParser.startElement(fElementQName, fAttributes, null); 131 break; 132 case XMLStreamConstants.END_ELEMENT: 133 EndElement end = currentEvent.asEndElement(); 134 fillQName(fElementQName, end.getName()); 135 fillDeclaredPrefixes(end); 136 fLocationWrapper.setLocation(end.getLocation()); 137 fSchemaDOMParser.endElement(fElementQName, null); 138 fNamespaceContext.popContext(); 139 --fDepth; 140 if (fDepth <= 0) { 141 break loop; 142 } 143 break; 144 case XMLStreamConstants.CHARACTERS: 145 sendCharactersToSchemaParser(currentEvent.asCharacters().getData(), false); 146 break; 147 case XMLStreamConstants.SPACE: 148 sendCharactersToSchemaParser(currentEvent.asCharacters().getData(), true); 149 break; 150 case XMLStreamConstants.CDATA: 151 fSchemaDOMParser.startCDATA(null); 152 sendCharactersToSchemaParser(currentEvent.asCharacters().getData(), false); 153 fSchemaDOMParser.endCDATA(null); 154 break; 155 case XMLStreamConstants.PROCESSING_INSTRUCTION: 156 ProcessingInstruction pi = (ProcessingInstruction)currentEvent; 157 fillProcessingInstruction(pi.getData()); 158 fSchemaDOMParser.processingInstruction(pi.getTarget(), fTempString, null); 159 break; 160 case XMLStreamConstants.DTD: 161 /* There shouldn't be a DTD in the schema */ 162 break; 163 case XMLStreamConstants.ENTITY_REFERENCE: 164 /* Not needed for schemas */ 165 break; 166 case XMLStreamConstants.COMMENT: 167 /* No point in sending comments */ 168 break; 169 case XMLStreamConstants.START_DOCUMENT: 170 fDepth++; 171 /* We automatically call startDocument before the loop */ 172 break; 173 case XMLStreamConstants.END_DOCUMENT: 174 /* We automatically call endDocument after the loop */ 175 break; 176 } 177 } 178 fLocationWrapper.setLocation(null); 179 fNamespaceContext.setNamespaceContext(null); 180 fSchemaDOMParser.endDocument(null); 181 } 182 } 183 184 public void parse(XMLStreamReader input) throws XMLStreamException, XNIException { 185 if (input.hasNext()) { 186 int eventType = input.getEventType(); 187 if (eventType != XMLStreamConstants.START_DOCUMENT && 188 eventType != XMLStreamConstants.START_ELEMENT) { 189 throw new XMLStreamException(); 190 } 191 fLocationWrapper.setLocation(input.getLocation()); 192 fSchemaDOMParser.startDocument(fLocationWrapper, null, fNamespaceContext, null); 193 boolean first = true; 194 loop: while (input.hasNext()) { 195 if (!first) { 196 eventType = input.next(); 197 } 198 else { 199 first = false; 200 } 201 switch (eventType) { 202 case XMLStreamConstants.START_ELEMENT: 203 ++fDepth; 204 fLocationWrapper.setLocation(input.getLocation()); 205 fNamespaceContext.setNamespaceContext(input.getNamespaceContext()); 206 fillQName(fElementQName, input.getNamespaceURI(), 207 input.getLocalName(), input.getPrefix()); 208 fillXMLAttributes(input); 209 fillDeclaredPrefixes(input); 210 addNamespaceDeclarations(); 211 fNamespaceContext.pushContext(); 212 fSchemaDOMParser.startElement(fElementQName, fAttributes, null); 213 break; 214 case XMLStreamConstants.END_ELEMENT: 215 fLocationWrapper.setLocation(input.getLocation()); 216 fNamespaceContext.setNamespaceContext(input.getNamespaceContext()); 217 fillQName(fElementQName, input.getNamespaceURI(), 218 input.getLocalName(), input.getPrefix()); 219 fillDeclaredPrefixes(input); 220 fSchemaDOMParser.endElement(fElementQName, null); 221 fNamespaceContext.popContext(); 222 --fDepth; 223 if (fDepth <= 0) { 224 break loop; 225 } 226 break; 227 case XMLStreamConstants.CHARACTERS: 228 fTempString.setValues(input.getTextCharacters(), 229 input.getTextStart(), input.getTextLength()); 230 fSchemaDOMParser.characters(fTempString, null); 231 break; 232 case XMLStreamConstants.SPACE: 233 fTempString.setValues(input.getTextCharacters(), 234 input.getTextStart(), input.getTextLength()); 235 fSchemaDOMParser.ignorableWhitespace(fTempString, null); 236 break; 237 case XMLStreamConstants.CDATA: 238 fSchemaDOMParser.startCDATA(null); 239 fTempString.setValues(input.getTextCharacters(), 240 input.getTextStart(), input.getTextLength()); 241 fSchemaDOMParser.characters(fTempString, null); 242 fSchemaDOMParser.endCDATA(null); 243 break; 244 case XMLStreamConstants.PROCESSING_INSTRUCTION: 245 fillProcessingInstruction(input.getPIData()); 246 fSchemaDOMParser.processingInstruction(input.getPITarget(), fTempString, null); 247 break; 248 case XMLStreamConstants.DTD: 249 /* There shouldn't be a DTD in the schema */ 250 break; 251 case XMLStreamConstants.ENTITY_REFERENCE: 252 /* Not needed for schemas */ 253 break; 254 case XMLStreamConstants.COMMENT: 255 /* No point in sending comments */ 256 break; 257 case XMLStreamConstants.START_DOCUMENT: 258 ++fDepth; 259 /* We automatically call startDocument before the loop */ 260 break; 261 case XMLStreamConstants.END_DOCUMENT: 262 /* We automatically call endDocument after the loop */ 263 break; 264 } 265 } 266 fLocationWrapper.setLocation(null); 267 fNamespaceContext.setNamespaceContext(null); 268 fSchemaDOMParser.endDocument(null); 269 } 270 } 271 272 /** Send characters to the validator in CHUNK_SIZE character chunks. */ 273 private void sendCharactersToSchemaParser(String str, boolean whitespace) { 274 if (str != null) { 275 final int length = str.length(); 276 final int remainder = length & CHUNK_MASK; 277 if (remainder > 0) { 278 str.getChars(0, remainder, fCharBuffer, 0); 279 fTempString.setValues(fCharBuffer, 0, remainder); 280 if (whitespace) { 281 fSchemaDOMParser.ignorableWhitespace(fTempString, null); 282 } 283 else { 284 fSchemaDOMParser.characters(fTempString, null); 285 } 286 } 287 int i = remainder; 288 while (i < length) { 289 str.getChars(i, i += CHUNK_SIZE, fCharBuffer, 0); 290 fTempString.setValues(fCharBuffer, 0, CHUNK_SIZE); 291 if (whitespace) { 292 fSchemaDOMParser.ignorableWhitespace(fTempString, null); 293 } 294 else { 295 fSchemaDOMParser.characters(fTempString, null); 296 } 297 } 298 } 299 } 300 301 // processing instructions must be sent all in one chunk 302 private void fillProcessingInstruction(String data) { 303 final int dataLength = data.length(); 304 char [] charBuffer = fCharBuffer; 305 if (charBuffer.length < dataLength) { 306 // toCharArray() creates a newly allocated array, so it's okay 307 // to keep a reference to it. 308 charBuffer = data.toCharArray(); 309 } 310 else { 311 data.getChars(0, dataLength, charBuffer, 0); 312 } 313 fTempString.setValues(charBuffer, 0, dataLength); 314 } 315 316 private void fillXMLAttributes(StartElement event) { 317 fAttributes.removeAllAttributes(); 318 final Iterator attrs = event.getAttributes(); 319 while (attrs.hasNext()) { 320 Attribute attr = (Attribute) attrs.next(); 321 fillQName(fAttributeQName, attr.getName()); 322 String type = attr.getDTDType(); 323 int idx = fAttributes.getLength(); 324 fAttributes.addAttributeNS(fAttributeQName, 325 (type != null) ? type : XMLSymbols.fCDATASymbol, attr.getValue()); 326 fAttributes.setSpecified(idx, attr.isSpecified()); 327 } 328 } 329 330 private void fillXMLAttributes(XMLStreamReader input) { 331 fAttributes.removeAllAttributes(); 332 final int len = input.getAttributeCount(); 333 for (int i = 0; i < len; ++i) { 334 fillQName(fAttributeQName, input.getAttributeNamespace(i), 335 input.getAttributeLocalName(i), input.getAttributePrefix(i)); 336 String type = input.getAttributeType(i); 337 fAttributes.addAttributeNS(fAttributeQName, 338 (type != null) ? type : XMLSymbols.fCDATASymbol, input.getAttributeValue(i)); 339 fAttributes.setSpecified(i, input.isAttributeSpecified(i)); 340 } 341 } 342 343 private void addNamespaceDeclarations() { 344 String prefix = null; 345 String localpart = null; 346 String rawname = null; 347 String nsPrefix = null; 348 String nsURI = null; 349 350 final Iterator iter = fDeclaredPrefixes.iterator(); 351 while (iter.hasNext()) { 352 nsPrefix = (String) iter.next(); 353 nsURI = fNamespaceContext.getURI(nsPrefix); 354 if (nsPrefix.length() > 0) { 355 prefix = XMLSymbols.PREFIX_XMLNS; 356 localpart = nsPrefix; 357 fStringBuffer.clear(); 358 fStringBuffer.append(prefix); 359 fStringBuffer.append(':'); 360 fStringBuffer.append(localpart); 361 rawname = fSymbolTable.addSymbol(fStringBuffer.ch, fStringBuffer.offset, fStringBuffer.length); 362 } 363 else { 364 prefix = XMLSymbols.EMPTY_STRING; 365 localpart = XMLSymbols.PREFIX_XMLNS; 366 rawname = XMLSymbols.PREFIX_XMLNS; 367 } 368 fAttributeQName.setValues(prefix, localpart, rawname, NamespaceContext.XMLNS_URI); 369 fAttributes.addAttribute(fAttributeQName, XMLSymbols.fCDATASymbol, 370 (nsURI != null) ? nsURI : XMLSymbols.EMPTY_STRING); 371 } 372 } 373 374 /** Fills in the list of declared prefixes. */ 375 private void fillDeclaredPrefixes(StartElement event) { 376 fillDeclaredPrefixes(event.getNamespaces()); 377 } 378 379 /** Fills in the list of declared prefixes. */ 380 private void fillDeclaredPrefixes(EndElement event) { 381 fillDeclaredPrefixes(event.getNamespaces()); 382 } 383 384 /** Fills in the list of declared prefixes. */ 385 private void fillDeclaredPrefixes(Iterator namespaces) { 386 fDeclaredPrefixes.clear(); 387 while (namespaces.hasNext()) { 388 Namespace ns = (Namespace) namespaces.next(); 389 String prefix = ns.getPrefix(); 390 fDeclaredPrefixes.add(prefix != null ? prefix : ""); 391 } 392 } 393 394 /** Fills in the list of declared prefixes. */ 395 private void fillDeclaredPrefixes(XMLStreamReader reader) { 396 fDeclaredPrefixes.clear(); 397 final int len = reader.getNamespaceCount(); 398 for (int i = 0; i < len; ++i) { 399 String prefix = reader.getNamespacePrefix(i); 400 fDeclaredPrefixes.add(prefix != null ? prefix : ""); 401 } 402 } 403 404 /** Fills in a QName object. */ 405 private void fillQName(QName toFill, javax.xml.namespace.QName toCopy) { 406 fillQName(toFill, toCopy.getNamespaceURI(), toCopy.getLocalPart(), toCopy.getPrefix()); 407 } 408 409 /** Fills in a QName object. */ 410 final void fillQName(QName toFill, String uri, String localpart, String prefix) { 411 uri = (uri != null && uri.length() > 0) ? fSymbolTable.addSymbol(uri) : null; 412 localpart = (localpart != null) ? fSymbolTable.addSymbol(localpart) : XMLSymbols.EMPTY_STRING; 413 prefix = (prefix != null && prefix.length() > 0) ? fSymbolTable.addSymbol(prefix) : XMLSymbols.EMPTY_STRING; 414 String raw = localpart; 415 if (prefix != XMLSymbols.EMPTY_STRING) { 416 fStringBuffer.clear(); 417 fStringBuffer.append(prefix); 418 fStringBuffer.append(':'); 419 fStringBuffer.append(localpart); 420 raw = fSymbolTable.addSymbol(fStringBuffer.ch, fStringBuffer.offset, fStringBuffer.length); 421 } 422 toFill.setValues(prefix, localpart, raw, uri); 423 } 424 425 } // StAXSchemaParser