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