src/share/jaxws_classes/com/sun/xml/internal/stream/buffer/stax/StreamReaderBufferProcessor.java

Thu, 31 Aug 2017 15:18:52 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:18:52 +0800
changeset 637
9c07ef4934dd
parent 397
b99d7e355d4b
parent 0
373ffda63c9a
permissions
-rw-r--r--

merge

aoqi@0 1 /*
aoqi@0 2 * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
aoqi@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
aoqi@0 4 *
aoqi@0 5 * This code is free software; you can redistribute it and/or modify it
aoqi@0 6 * under the terms of the GNU General Public License version 2 only, as
aoqi@0 7 * published by the Free Software Foundation. Oracle designates this
aoqi@0 8 * particular file as subject to the "Classpath" exception as provided
aoqi@0 9 * by Oracle in the LICENSE file that accompanied this code.
aoqi@0 10 *
aoqi@0 11 * This code is distributed in the hope that it will be useful, but WITHOUT
aoqi@0 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
aoqi@0 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
aoqi@0 14 * version 2 for more details (a copy is included in the LICENSE file that
aoqi@0 15 * accompanied this code).
aoqi@0 16 *
aoqi@0 17 * You should have received a copy of the GNU General Public License version
aoqi@0 18 * 2 along with this work; if not, write to the Free Software Foundation,
aoqi@0 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
aoqi@0 20 *
aoqi@0 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
aoqi@0 22 * or visit www.oracle.com if you need additional information or have any
aoqi@0 23 * questions.
aoqi@0 24 */
aoqi@0 25
aoqi@0 26 package com.sun.xml.internal.stream.buffer.stax;
aoqi@0 27
aoqi@0 28 import com.sun.xml.internal.stream.buffer.AbstractProcessor;
aoqi@0 29 import com.sun.xml.internal.stream.buffer.AttributesHolder;
aoqi@0 30 import com.sun.xml.internal.stream.buffer.XMLStreamBuffer;
aoqi@0 31 import com.sun.xml.internal.stream.buffer.XMLStreamBufferMark;
aoqi@0 32 import com.sun.xml.internal.org.jvnet.staxex.NamespaceContextEx;
aoqi@0 33 import com.sun.xml.internal.org.jvnet.staxex.XMLStreamReaderEx;
aoqi@0 34
aoqi@0 35 import javax.xml.XMLConstants;
aoqi@0 36 import javax.xml.namespace.QName;
aoqi@0 37 import javax.xml.stream.Location;
aoqi@0 38 import javax.xml.stream.XMLStreamException;
aoqi@0 39 import javax.xml.stream.XMLStreamReader;
aoqi@0 40 import java.util.*;
aoqi@0 41
aoqi@0 42 /**
aoqi@0 43 * A processor of a {@link XMLStreamBuffer} that reads the XML infoset as
aoqi@0 44 * {@link XMLStreamReader}.
aoqi@0 45 *
aoqi@0 46 * <p>
aoqi@0 47 * Because of {@link XMLStreamReader} design, this processor always produce
aoqi@0 48 * a full document infoset, even if the buffer just contains a fragment.
aoqi@0 49 *
aoqi@0 50 * <p>
aoqi@0 51 * When {@link XMLStreamBuffer} contains a multiple tree (AKA "forest"),
aoqi@0 52 * {@link XMLStreamReader} will behave as if there are multiple root elements
aoqi@0 53 * (so you'll see {@link #START_ELEMENT} event where you'd normally expect
aoqi@0 54 * {@link #END_DOCUMENT}.)
aoqi@0 55 *
aoqi@0 56 * @author Paul.Sandoz@Sun.Com
aoqi@0 57 * @author K.Venugopal@sun.com
aoqi@0 58 */
aoqi@0 59 public class StreamReaderBufferProcessor extends AbstractProcessor implements XMLStreamReaderEx {
aoqi@0 60 private static final int CACHE_SIZE = 16;
aoqi@0 61
aoqi@0 62 // Stack to hold element and namespace declaration information
aoqi@0 63 protected ElementStackEntry[] _stack = new ElementStackEntry[CACHE_SIZE];
aoqi@0 64 /** The top-most active entry of the {@link #_stack}. */
aoqi@0 65 protected ElementStackEntry _stackTop;
aoqi@0 66 /** The element depth that we are in. Used to determine when we are done with a tree. */
aoqi@0 67 protected int _depth;
aoqi@0 68
aoqi@0 69 // Arrays to hold all namespace declarations
aoqi@0 70 /**
aoqi@0 71 * Namespace prefixes. Can be empty but not null.
aoqi@0 72 */
aoqi@0 73 protected String[] _namespaceAIIsPrefix = new String[CACHE_SIZE];
aoqi@0 74 protected String[] _namespaceAIIsNamespaceName = new String[CACHE_SIZE];
aoqi@0 75 protected int _namespaceAIIsEnd;
aoqi@0 76
aoqi@0 77 // Internal namespace context implementation
aoqi@0 78 protected InternalNamespaceContext _nsCtx = new InternalNamespaceContext();
aoqi@0 79
aoqi@0 80 // The current event type
aoqi@0 81 protected int _eventType;
aoqi@0 82
aoqi@0 83 /**
aoqi@0 84 * Holder of the attributes.
aoqi@0 85 *
aoqi@0 86 * Be careful that this follows the SAX convention of using "" instead of null.
aoqi@0 87 */
aoqi@0 88 protected AttributesHolder _attributeCache;
aoqi@0 89
aoqi@0 90 // Characters as a CharSequence
aoqi@0 91 protected CharSequence _charSequence;
aoqi@0 92
aoqi@0 93 // Characters as a char array with offset and length
aoqi@0 94 protected char[] _characters;
aoqi@0 95 protected int _textOffset;
aoqi@0 96 protected int _textLen;
aoqi@0 97
aoqi@0 98 protected String _piTarget;
aoqi@0 99 protected String _piData;
aoqi@0 100
aoqi@0 101 //
aoqi@0 102 // Represents the parser state wrt the end of parsing.
aoqi@0 103 //
aoqi@0 104 /**
aoqi@0 105 * The parser is in the middle of parsing a document,
aoqi@0 106 * with no end in sight.
aoqi@0 107 */
aoqi@0 108 private static final int PARSING = 1;
aoqi@0 109 /**
aoqi@0 110 * The parser has already reported the {@link #END_ELEMENT},
aoqi@0 111 * and we are parsing a fragment. We'll report {@link #END_DOCUMENT}
aoqi@0 112 * next and be done.
aoqi@0 113 */
aoqi@0 114 private static final int PENDING_END_DOCUMENT = 2;
aoqi@0 115 /**
aoqi@0 116 * The parser has reported the {@link #END_DOCUMENT} event,
aoqi@0 117 * so we are really done parsing.
aoqi@0 118 */
aoqi@0 119 private static final int COMPLETED = 3;
aoqi@0 120
aoqi@0 121 /**
aoqi@0 122 * True if processing is complete.
aoqi@0 123 */
aoqi@0 124 private int _completionState;
aoqi@0 125
aoqi@0 126 public StreamReaderBufferProcessor() {
aoqi@0 127 for (int i=0; i < _stack.length; i++){
aoqi@0 128 _stack[i] = new ElementStackEntry();
aoqi@0 129 }
aoqi@0 130
aoqi@0 131 _attributeCache = new AttributesHolder();
aoqi@0 132 }
aoqi@0 133
aoqi@0 134 public StreamReaderBufferProcessor(XMLStreamBuffer buffer) throws XMLStreamException {
aoqi@0 135 this();
aoqi@0 136 setXMLStreamBuffer(buffer);
aoqi@0 137 }
aoqi@0 138
aoqi@0 139 public void setXMLStreamBuffer(XMLStreamBuffer buffer) throws XMLStreamException {
aoqi@0 140 setBuffer(buffer,buffer.isFragment());
aoqi@0 141
aoqi@0 142 _completionState = PARSING;
aoqi@0 143 _namespaceAIIsEnd = 0;
aoqi@0 144 _characters = null;
aoqi@0 145 _charSequence = null;
aoqi@0 146 _eventType = START_DOCUMENT;
aoqi@0 147 }
aoqi@0 148
aoqi@0 149 /**
aoqi@0 150 * Does {@link #nextTag()} and if the parser moved to a new start tag,
aoqi@0 151 * returns a {@link XMLStreamBufferMark} that captures the infoset starting
aoqi@0 152 * from the newly discovered element.
aoqi@0 153 *
aoqi@0 154 * <p>
aoqi@0 155 * (Ideally we should have a method that works against the current position,
aoqi@0 156 * but the way the data structure is read makes this somewhat difficult.)
aoqi@0 157 *
aoqi@0 158 * This creates a new {@link XMLStreamBufferMark} that shares the underlying
aoqi@0 159 * data storage, thus it's fairly efficient.
aoqi@0 160 */
aoqi@0 161 public XMLStreamBuffer nextTagAndMark() throws XMLStreamException {
aoqi@0 162 while (true) {
aoqi@0 163 int s = peekStructure();
aoqi@0 164 if((s &TYPE_MASK)==T_ELEMENT) {
aoqi@0 165 // next is start element.
aoqi@0 166 Map<String,String> inscope = new HashMap<String, String>(_namespaceAIIsEnd);
aoqi@0 167
aoqi@0 168 for (int i=0 ; i<_namespaceAIIsEnd; i++)
aoqi@0 169 inscope.put(_namespaceAIIsPrefix[i],_namespaceAIIsNamespaceName[i]);
aoqi@0 170
aoqi@0 171 XMLStreamBufferMark mark = new XMLStreamBufferMark(inscope, this);
aoqi@0 172 next();
aoqi@0 173 return mark;
aoqi@0 174 } else if((s &TYPE_MASK)==T_DOCUMENT) {
aoqi@0 175 //move the pointer to next structure.
aoqi@0 176 readStructure();
aoqi@0 177 //mark the next start element
aoqi@0 178 XMLStreamBufferMark mark = new XMLStreamBufferMark(new HashMap<String, String>(_namespaceAIIsEnd), this);
aoqi@0 179 next();
aoqi@0 180 return mark;
aoqi@0 181 }
aoqi@0 182
aoqi@0 183 if(next()==END_ELEMENT)
aoqi@0 184 return null;
aoqi@0 185 }
aoqi@0 186 }
aoqi@0 187
aoqi@0 188 public Object getProperty(String name) {
aoqi@0 189 return null;
aoqi@0 190 }
aoqi@0 191
aoqi@0 192 public int next() throws XMLStreamException {
aoqi@0 193 switch(_completionState) {
aoqi@0 194 case COMPLETED:
aoqi@0 195 throw new XMLStreamException("Invalid State");
aoqi@0 196 case PENDING_END_DOCUMENT:
aoqi@0 197 _namespaceAIIsEnd = 0;
aoqi@0 198 _completionState = COMPLETED;
aoqi@0 199 return _eventType = END_DOCUMENT;
aoqi@0 200 }
aoqi@0 201
aoqi@0 202 // Pop the stack of elements
aoqi@0 203 // This is a post-processing operation
aoqi@0 204 // The stack of the element should be poppoed after
aoqi@0 205 // the END_ELEMENT event is returned so that the correct element name
aoqi@0 206 // and namespace scope is returned
aoqi@0 207 switch(_eventType) {
aoqi@0 208 case END_ELEMENT:
aoqi@0 209 if (_depth > 1) {
aoqi@0 210 _depth--;
aoqi@0 211 // _depth index is always set to the next free stack entry
aoqi@0 212 // to push
aoqi@0 213 popElementStack(_depth);
aoqi@0 214 } else if (_depth == 1) {
aoqi@0 215 _depth--;
aoqi@0 216 }
aoqi@0 217 }
aoqi@0 218
aoqi@0 219 _characters = null;
aoqi@0 220 _charSequence = null;
aoqi@0 221 while(true) {// loop only if we read STATE_DOCUMENT
aoqi@0 222 int eiiState = readEiiState();
aoqi@0 223 switch(eiiState) {
aoqi@0 224 case STATE_DOCUMENT:
aoqi@0 225 // we'll always produce a full document, and we've already report START_DOCUMENT event.
aoqi@0 226 // so simply skil this
aoqi@0 227 continue;
aoqi@0 228 case STATE_ELEMENT_U_LN_QN: {
aoqi@0 229 final String uri = readStructureString();
aoqi@0 230 final String localName = readStructureString();
aoqi@0 231 final String prefix = getPrefixFromQName(readStructureString());
aoqi@0 232
aoqi@0 233 processElement(prefix, uri, localName, isInscope(_depth));
aoqi@0 234 return _eventType = START_ELEMENT;
aoqi@0 235 }
aoqi@0 236 case STATE_ELEMENT_P_U_LN:
aoqi@0 237 processElement(readStructureString(), readStructureString(), readStructureString(),isInscope(_depth));
aoqi@0 238 return _eventType = START_ELEMENT;
aoqi@0 239 case STATE_ELEMENT_U_LN:
aoqi@0 240 processElement(null, readStructureString(), readStructureString(),isInscope(_depth));
aoqi@0 241 return _eventType = START_ELEMENT;
aoqi@0 242 case STATE_ELEMENT_LN:
aoqi@0 243 processElement(null, null, readStructureString(),isInscope(_depth));
aoqi@0 244 return _eventType = START_ELEMENT;
aoqi@0 245 case STATE_TEXT_AS_CHAR_ARRAY_SMALL:
aoqi@0 246 _textLen = readStructure();
aoqi@0 247 _textOffset = readContentCharactersBuffer(_textLen);
aoqi@0 248 _characters = _contentCharactersBuffer;
aoqi@0 249
aoqi@0 250 return _eventType = CHARACTERS;
aoqi@0 251 case STATE_TEXT_AS_CHAR_ARRAY_MEDIUM:
aoqi@0 252 _textLen = readStructure16();
aoqi@0 253 _textOffset = readContentCharactersBuffer(_textLen);
aoqi@0 254 _characters = _contentCharactersBuffer;
aoqi@0 255
aoqi@0 256 return _eventType = CHARACTERS;
aoqi@0 257 case STATE_TEXT_AS_CHAR_ARRAY_COPY:
aoqi@0 258 _characters = readContentCharactersCopy();
aoqi@0 259 _textLen = _characters.length;
aoqi@0 260 _textOffset = 0;
aoqi@0 261
aoqi@0 262 return _eventType = CHARACTERS;
aoqi@0 263 case STATE_TEXT_AS_STRING:
aoqi@0 264 _eventType = CHARACTERS;
aoqi@0 265 _charSequence = readContentString();
aoqi@0 266
aoqi@0 267 return _eventType = CHARACTERS;
aoqi@0 268 case STATE_TEXT_AS_OBJECT:
aoqi@0 269 _eventType = CHARACTERS;
aoqi@0 270 _charSequence = (CharSequence)readContentObject();
aoqi@0 271
aoqi@0 272 return _eventType = CHARACTERS;
aoqi@0 273 case STATE_COMMENT_AS_CHAR_ARRAY_SMALL:
aoqi@0 274 _textLen = readStructure();
aoqi@0 275 _textOffset = readContentCharactersBuffer(_textLen);
aoqi@0 276 _characters = _contentCharactersBuffer;
aoqi@0 277
aoqi@0 278 return _eventType = COMMENT;
aoqi@0 279 case STATE_COMMENT_AS_CHAR_ARRAY_MEDIUM:
aoqi@0 280 _textLen = readStructure16();
aoqi@0 281 _textOffset = readContentCharactersBuffer(_textLen);
aoqi@0 282 _characters = _contentCharactersBuffer;
aoqi@0 283
aoqi@0 284 return _eventType = COMMENT;
aoqi@0 285 case STATE_COMMENT_AS_CHAR_ARRAY_COPY:
aoqi@0 286 _characters = readContentCharactersCopy();
aoqi@0 287 _textLen = _characters.length;
aoqi@0 288 _textOffset = 0;
aoqi@0 289
aoqi@0 290 return _eventType = COMMENT;
aoqi@0 291 case STATE_COMMENT_AS_STRING:
aoqi@0 292 _charSequence = readContentString();
aoqi@0 293
aoqi@0 294 return _eventType = COMMENT;
aoqi@0 295 case STATE_PROCESSING_INSTRUCTION:
aoqi@0 296 _piTarget = readStructureString();
aoqi@0 297 _piData = readStructureString();
aoqi@0 298
aoqi@0 299 return _eventType = PROCESSING_INSTRUCTION;
aoqi@0 300 case STATE_END:
aoqi@0 301 if (_depth > 1) {
aoqi@0 302 // normal case
aoqi@0 303 return _eventType = END_ELEMENT;
aoqi@0 304 } else if (_depth == 1) {
aoqi@0 305 // this is the last end element for the current tree.
aoqi@0 306 if (_fragmentMode) {
aoqi@0 307 if(--_treeCount==0) // is this the last tree in the forest?
aoqi@0 308 _completionState = PENDING_END_DOCUMENT;
aoqi@0 309 }
aoqi@0 310 return _eventType = END_ELEMENT;
aoqi@0 311 } else {
aoqi@0 312 // this only happens when we are processing a full document
aoqi@0 313 // and we hit the "end of document" marker
aoqi@0 314 _namespaceAIIsEnd = 0;
aoqi@0 315 _completionState = COMPLETED;
aoqi@0 316 return _eventType = END_DOCUMENT;
aoqi@0 317 }
aoqi@0 318 default:
aoqi@0 319 throw new XMLStreamException("Internal XSB error: Invalid State="+eiiState);
aoqi@0 320 }
aoqi@0 321 // this should be unreachable
aoqi@0 322 }
aoqi@0 323 }
aoqi@0 324
aoqi@0 325 public final void require(int type, String namespaceURI, String localName) throws XMLStreamException {
aoqi@0 326 if( type != _eventType) {
aoqi@0 327 throw new XMLStreamException("");
aoqi@0 328 }
aoqi@0 329 if( namespaceURI != null && !namespaceURI.equals(getNamespaceURI())) {
aoqi@0 330 throw new XMLStreamException("");
aoqi@0 331 }
aoqi@0 332 if(localName != null && !localName.equals(getLocalName())) {
aoqi@0 333 throw new XMLStreamException("");
aoqi@0 334 }
aoqi@0 335 }
aoqi@0 336
aoqi@0 337 public final String getElementTextTrim() throws XMLStreamException {
aoqi@0 338 // TODO getElementText* methods more efficiently
aoqi@0 339 return getElementText().trim();
aoqi@0 340 }
aoqi@0 341
aoqi@0 342 public final String getElementText() throws XMLStreamException {
aoqi@0 343 if(_eventType != START_ELEMENT) {
aoqi@0 344 throw new XMLStreamException("");
aoqi@0 345 }
aoqi@0 346
aoqi@0 347 next();
aoqi@0 348 return getElementText(true);
aoqi@0 349 }
aoqi@0 350
aoqi@0 351 public final String getElementText(boolean startElementRead) throws XMLStreamException {
aoqi@0 352 if (!startElementRead) {
aoqi@0 353 throw new XMLStreamException("");
aoqi@0 354 }
aoqi@0 355
aoqi@0 356 int eventType = getEventType();
aoqi@0 357 StringBuilder content = new StringBuilder();
aoqi@0 358 while(eventType != END_ELEMENT ) {
aoqi@0 359 if(eventType == CHARACTERS
aoqi@0 360 || eventType == CDATA
aoqi@0 361 || eventType == SPACE
aoqi@0 362 || eventType == ENTITY_REFERENCE) {
aoqi@0 363 content.append(getText());
aoqi@0 364 } else if(eventType == PROCESSING_INSTRUCTION
aoqi@0 365 || eventType == COMMENT) {
aoqi@0 366 // skipping
aoqi@0 367 } else if(eventType == END_DOCUMENT) {
aoqi@0 368 throw new XMLStreamException("");
aoqi@0 369 } else if(eventType == START_ELEMENT) {
aoqi@0 370 throw new XMLStreamException("");
aoqi@0 371 } else {
aoqi@0 372 throw new XMLStreamException("");
aoqi@0 373 }
aoqi@0 374 eventType = next();
aoqi@0 375 }
aoqi@0 376 return content.toString();
aoqi@0 377 }
aoqi@0 378
aoqi@0 379 public final int nextTag() throws XMLStreamException {
aoqi@0 380 next();
aoqi@0 381 return nextTag(true);
aoqi@0 382 }
aoqi@0 383
aoqi@0 384 public final int nextTag(boolean currentTagRead) throws XMLStreamException {
aoqi@0 385 int eventType = getEventType();
aoqi@0 386 if (!currentTagRead) {
aoqi@0 387 eventType = next();
aoqi@0 388 }
aoqi@0 389 while((eventType == CHARACTERS && isWhiteSpace()) // skip whitespace
aoqi@0 390 || (eventType == CDATA && isWhiteSpace())
aoqi@0 391 || eventType == SPACE
aoqi@0 392 || eventType == PROCESSING_INSTRUCTION
aoqi@0 393 || eventType == COMMENT) {
aoqi@0 394 eventType = next();
aoqi@0 395 }
aoqi@0 396 if (eventType != START_ELEMENT && eventType != END_ELEMENT) {
aoqi@0 397 throw new XMLStreamException("");
aoqi@0 398 }
aoqi@0 399 return eventType;
aoqi@0 400 }
aoqi@0 401
aoqi@0 402 public final boolean hasNext() {
aoqi@0 403 return (_eventType != END_DOCUMENT);
aoqi@0 404 }
aoqi@0 405
aoqi@0 406 public void close() throws XMLStreamException {
aoqi@0 407 }
aoqi@0 408
aoqi@0 409 public final boolean isStartElement() {
aoqi@0 410 return (_eventType == START_ELEMENT);
aoqi@0 411 }
aoqi@0 412
aoqi@0 413 public final boolean isEndElement() {
aoqi@0 414 return (_eventType == END_ELEMENT);
aoqi@0 415 }
aoqi@0 416
aoqi@0 417 public final boolean isCharacters() {
aoqi@0 418 return (_eventType == CHARACTERS);
aoqi@0 419 }
aoqi@0 420
aoqi@0 421 public final boolean isWhiteSpace() {
aoqi@0 422 if(isCharacters() || (_eventType == CDATA)){
aoqi@0 423 char [] ch = this.getTextCharacters();
aoqi@0 424 int start = this.getTextStart();
aoqi@0 425 int length = this.getTextLength();
aoqi@0 426 for (int i = start; i < length; i++){
aoqi@0 427 final char c = ch[i];
aoqi@0 428 if (!(c == 0x20 || c == 0x9 || c == 0xD || c == 0xA))
aoqi@0 429 return false;
aoqi@0 430 }
aoqi@0 431 return true;
aoqi@0 432 }
aoqi@0 433 return false;
aoqi@0 434 }
aoqi@0 435
aoqi@0 436 public final String getAttributeValue(String namespaceURI, String localName) {
aoqi@0 437 if (_eventType != START_ELEMENT) {
aoqi@0 438 throw new IllegalStateException("");
aoqi@0 439 }
aoqi@0 440
aoqi@0 441 if (namespaceURI == null) {
aoqi@0 442 // Set to the empty string to be compatible with the
aoqi@0 443 // org.xml.sax.Attributes interface
aoqi@0 444 namespaceURI = "";
aoqi@0 445 }
aoqi@0 446
aoqi@0 447 return _attributeCache.getValue(namespaceURI, localName);
aoqi@0 448 }
aoqi@0 449
aoqi@0 450 public final int getAttributeCount() {
aoqi@0 451 if (_eventType != START_ELEMENT) {
aoqi@0 452 throw new IllegalStateException("");
aoqi@0 453 }
aoqi@0 454
aoqi@0 455 return _attributeCache.getLength();
aoqi@0 456 }
aoqi@0 457
aoqi@0 458 public final javax.xml.namespace.QName getAttributeName(int index) {
aoqi@0 459 if (_eventType != START_ELEMENT) {
aoqi@0 460 throw new IllegalStateException("");
aoqi@0 461 }
aoqi@0 462
aoqi@0 463 final String prefix = _attributeCache.getPrefix(index);
aoqi@0 464 final String localName = _attributeCache.getLocalName(index);
aoqi@0 465 final String uri = _attributeCache.getURI(index);
aoqi@0 466 return new QName(uri,localName,prefix);
aoqi@0 467 }
aoqi@0 468
aoqi@0 469
aoqi@0 470 public final String getAttributeNamespace(int index) {
aoqi@0 471 if (_eventType != START_ELEMENT) {
aoqi@0 472 throw new IllegalStateException("");
aoqi@0 473 }
aoqi@0 474 return fixEmptyString(_attributeCache.getURI(index));
aoqi@0 475 }
aoqi@0 476
aoqi@0 477 public final String getAttributeLocalName(int index) {
aoqi@0 478 if (_eventType != START_ELEMENT) {
aoqi@0 479 throw new IllegalStateException("");
aoqi@0 480 }
aoqi@0 481 return _attributeCache.getLocalName(index);
aoqi@0 482 }
aoqi@0 483
aoqi@0 484 public final String getAttributePrefix(int index) {
aoqi@0 485 if (_eventType != START_ELEMENT) {
aoqi@0 486 throw new IllegalStateException("");
aoqi@0 487 }
aoqi@0 488 return fixEmptyString(_attributeCache.getPrefix(index));
aoqi@0 489 }
aoqi@0 490
aoqi@0 491 public final String getAttributeType(int index) {
aoqi@0 492 if (_eventType != START_ELEMENT) {
aoqi@0 493 throw new IllegalStateException("");
aoqi@0 494 }
aoqi@0 495 return _attributeCache.getType(index);
aoqi@0 496 }
aoqi@0 497
aoqi@0 498 public final String getAttributeValue(int index) {
aoqi@0 499 if (_eventType != START_ELEMENT) {
aoqi@0 500 throw new IllegalStateException("");
aoqi@0 501 }
aoqi@0 502
aoqi@0 503 return _attributeCache.getValue(index);
aoqi@0 504 }
aoqi@0 505
aoqi@0 506 public final boolean isAttributeSpecified(int index) {
aoqi@0 507 return false;
aoqi@0 508 }
aoqi@0 509
aoqi@0 510 public final int getNamespaceCount() {
aoqi@0 511 if (_eventType == START_ELEMENT || _eventType == END_ELEMENT) {
aoqi@0 512 return _stackTop.namespaceAIIsEnd - _stackTop.namespaceAIIsStart;
aoqi@0 513 }
aoqi@0 514
aoqi@0 515 throw new IllegalStateException("");
aoqi@0 516 }
aoqi@0 517
aoqi@0 518 public final String getNamespacePrefix(int index) {
aoqi@0 519 if (_eventType == START_ELEMENT || _eventType == END_ELEMENT) {
aoqi@0 520 return _namespaceAIIsPrefix[_stackTop.namespaceAIIsStart + index];
aoqi@0 521 }
aoqi@0 522
aoqi@0 523 throw new IllegalStateException("");
aoqi@0 524 }
aoqi@0 525
aoqi@0 526 public final String getNamespaceURI(int index) {
aoqi@0 527 if (_eventType == START_ELEMENT || _eventType == END_ELEMENT) {
aoqi@0 528 return _namespaceAIIsNamespaceName[_stackTop.namespaceAIIsStart + index];
aoqi@0 529 }
aoqi@0 530
aoqi@0 531 throw new IllegalStateException("");
aoqi@0 532 }
aoqi@0 533
aoqi@0 534 public final String getNamespaceURI(String prefix) {
aoqi@0 535 return _nsCtx.getNamespaceURI(prefix);
aoqi@0 536 }
aoqi@0 537
aoqi@0 538 public final NamespaceContextEx getNamespaceContext() {
aoqi@0 539 return _nsCtx;
aoqi@0 540 }
aoqi@0 541
aoqi@0 542 public final int getEventType() {
aoqi@0 543 return _eventType;
aoqi@0 544 }
aoqi@0 545
aoqi@0 546 public final String getText() {
aoqi@0 547 if (_characters != null) {
aoqi@0 548 String s = new String(_characters, _textOffset, _textLen);
aoqi@0 549 _charSequence = s;
aoqi@0 550 return s;
aoqi@0 551 } else if (_charSequence != null) {
aoqi@0 552 return _charSequence.toString();
aoqi@0 553 } else {
aoqi@0 554 throw new IllegalStateException();
aoqi@0 555 }
aoqi@0 556 }
aoqi@0 557
aoqi@0 558 public final char[] getTextCharacters() {
aoqi@0 559 if (_characters != null) {
aoqi@0 560 return _characters;
aoqi@0 561 } else if (_charSequence != null) {
aoqi@0 562 // TODO try to avoid creation of a temporary String for some
aoqi@0 563 // CharSequence implementations
aoqi@0 564 _characters = _charSequence.toString().toCharArray();
aoqi@0 565 _textLen = _characters.length;
aoqi@0 566 _textOffset = 0;
aoqi@0 567 return _characters;
aoqi@0 568 } else {
aoqi@0 569 throw new IllegalStateException();
aoqi@0 570 }
aoqi@0 571 }
aoqi@0 572
aoqi@0 573 public final int getTextStart() {
aoqi@0 574 if (_characters != null) {
aoqi@0 575 return _textOffset;
aoqi@0 576 } else if (_charSequence != null) {
aoqi@0 577 return 0;
aoqi@0 578 } else {
aoqi@0 579 throw new IllegalStateException();
aoqi@0 580 }
aoqi@0 581 }
aoqi@0 582
aoqi@0 583 public final int getTextLength() {
aoqi@0 584 if (_characters != null) {
aoqi@0 585 return _textLen;
aoqi@0 586 } else if (_charSequence != null) {
aoqi@0 587 return _charSequence.length();
aoqi@0 588 } else {
aoqi@0 589 throw new IllegalStateException();
aoqi@0 590 }
aoqi@0 591 }
aoqi@0 592
aoqi@0 593 public final int getTextCharacters(int sourceStart, char[] target,
aoqi@0 594 int targetStart, int length) throws XMLStreamException {
aoqi@0 595 if (_characters != null) {
aoqi@0 596 } else if (_charSequence != null) {
aoqi@0 597 _characters = _charSequence.toString().toCharArray();
aoqi@0 598 _textLen = _characters.length;
aoqi@0 599 _textOffset = 0;
aoqi@0 600 } else {
aoqi@0 601 throw new IllegalStateException("");
aoqi@0 602 }
aoqi@0 603
aoqi@0 604 try {
aoqi@0 605 int remaining = _textLen - sourceStart;
aoqi@0 606 int len = remaining > length ? length : remaining;
aoqi@0 607 sourceStart += _textOffset;
aoqi@0 608 System.arraycopy(_characters, sourceStart, target, targetStart, len);
aoqi@0 609 return len;
aoqi@0 610 } catch (IndexOutOfBoundsException e) {
aoqi@0 611 throw new XMLStreamException(e);
aoqi@0 612 }
aoqi@0 613 }
aoqi@0 614
aoqi@0 615 private class CharSequenceImpl implements CharSequence {
aoqi@0 616 private final int _offset;
aoqi@0 617 private final int _length;
aoqi@0 618
aoqi@0 619 CharSequenceImpl(int offset, int length) {
aoqi@0 620 _offset = offset;
aoqi@0 621 _length = length;
aoqi@0 622 }
aoqi@0 623
aoqi@0 624 public int length() {
aoqi@0 625 return _length;
aoqi@0 626 }
aoqi@0 627
aoqi@0 628 public char charAt(int index) {
aoqi@0 629 if (index >= 0 && index < _textLen) {
aoqi@0 630 return _characters[_textOffset + index];
aoqi@0 631 } else {
aoqi@0 632 throw new IndexOutOfBoundsException();
aoqi@0 633 }
aoqi@0 634 }
aoqi@0 635
aoqi@0 636 public CharSequence subSequence(int start, int end) {
aoqi@0 637 final int length = end - start;
aoqi@0 638 if (end < 0 || start < 0 || end > length || start > end) {
aoqi@0 639 throw new IndexOutOfBoundsException();
aoqi@0 640 }
aoqi@0 641
aoqi@0 642 return new CharSequenceImpl(_offset + start, length);
aoqi@0 643 }
aoqi@0 644
aoqi@0 645 @Override
aoqi@0 646 public String toString() {
aoqi@0 647 return new String(_characters, _offset, _length);
aoqi@0 648 }
aoqi@0 649 }
aoqi@0 650
aoqi@0 651 public final CharSequence getPCDATA() {
aoqi@0 652 if (_characters != null) {
aoqi@0 653 return new CharSequenceImpl(_textOffset, _textLen);
aoqi@0 654 } else if (_charSequence != null) {
aoqi@0 655 return _charSequence;
aoqi@0 656 } else {
aoqi@0 657 throw new IllegalStateException();
aoqi@0 658 }
aoqi@0 659 }
aoqi@0 660
aoqi@0 661 public final String getEncoding() {
aoqi@0 662 return "UTF-8";
aoqi@0 663 }
aoqi@0 664
aoqi@0 665 public final boolean hasText() {
aoqi@0 666 return (_characters != null || _charSequence != null);
aoqi@0 667 }
aoqi@0 668
aoqi@0 669 public final Location getLocation() {
aoqi@0 670 return new DummyLocation();
aoqi@0 671 }
aoqi@0 672
aoqi@0 673 public final boolean hasName() {
aoqi@0 674 return (_eventType == START_ELEMENT || _eventType == END_ELEMENT);
aoqi@0 675 }
aoqi@0 676
aoqi@0 677 public final QName getName() {
aoqi@0 678 return _stackTop.getQName();
aoqi@0 679 }
aoqi@0 680
aoqi@0 681 public final String getLocalName() {
aoqi@0 682 return _stackTop.localName;
aoqi@0 683 }
aoqi@0 684
aoqi@0 685 public final String getNamespaceURI() {
aoqi@0 686 return _stackTop.uri;
aoqi@0 687 }
aoqi@0 688
aoqi@0 689 public final String getPrefix() {
aoqi@0 690 return _stackTop.prefix;
aoqi@0 691
aoqi@0 692 }
aoqi@0 693
aoqi@0 694 public final String getVersion() {
aoqi@0 695 return "1.0";
aoqi@0 696 }
aoqi@0 697
aoqi@0 698 public final boolean isStandalone() {
aoqi@0 699 return false;
aoqi@0 700 }
aoqi@0 701
aoqi@0 702 public final boolean standaloneSet() {
aoqi@0 703 return false;
aoqi@0 704 }
aoqi@0 705
aoqi@0 706 public final String getCharacterEncodingScheme() {
aoqi@0 707 return "UTF-8";
aoqi@0 708 }
aoqi@0 709
aoqi@0 710 public final String getPITarget() {
aoqi@0 711 if (_eventType == PROCESSING_INSTRUCTION) {
aoqi@0 712 return _piTarget;
aoqi@0 713 }
aoqi@0 714 throw new IllegalStateException("");
aoqi@0 715 }
aoqi@0 716
aoqi@0 717 public final String getPIData() {
aoqi@0 718 if (_eventType == PROCESSING_INSTRUCTION) {
aoqi@0 719 return _piData;
aoqi@0 720 }
aoqi@0 721 throw new IllegalStateException("");
aoqi@0 722 }
aoqi@0 723
aoqi@0 724 protected void processElement(String prefix, String uri, String localName, boolean inscope) {
aoqi@0 725 pushElementStack();
aoqi@0 726 _stackTop.set(prefix, uri, localName);
aoqi@0 727
aoqi@0 728 _attributeCache.clear();
aoqi@0 729
aoqi@0 730 int item = peekStructure();
aoqi@0 731 if ((item & TYPE_MASK) == T_NAMESPACE_ATTRIBUTE || inscope) {
aoqi@0 732 // Skip the namespace declarations on the element
aoqi@0 733 // they will have been added already
aoqi@0 734 item = processNamespaceAttributes(item, inscope);
aoqi@0 735 }
aoqi@0 736 if ((item & TYPE_MASK) == T_ATTRIBUTE) {
aoqi@0 737 processAttributes(item);
aoqi@0 738 }
aoqi@0 739 }
aoqi@0 740
aoqi@0 741 private boolean isInscope(int depth) {
aoqi@0 742 return _buffer.getInscopeNamespaces().size() > 0 && depth ==0;
aoqi@0 743 }
aoqi@0 744
aoqi@0 745 private void resizeNamespaceAttributes() {
aoqi@0 746 final String[] namespaceAIIsPrefix = new String[_namespaceAIIsEnd * 2];
aoqi@0 747 System.arraycopy(_namespaceAIIsPrefix, 0, namespaceAIIsPrefix, 0, _namespaceAIIsEnd);
aoqi@0 748 _namespaceAIIsPrefix = namespaceAIIsPrefix;
aoqi@0 749
aoqi@0 750 final String[] namespaceAIIsNamespaceName = new String[_namespaceAIIsEnd * 2];
aoqi@0 751 System.arraycopy(_namespaceAIIsNamespaceName, 0, namespaceAIIsNamespaceName, 0, _namespaceAIIsEnd);
aoqi@0 752 _namespaceAIIsNamespaceName = namespaceAIIsNamespaceName;
aoqi@0 753 }
aoqi@0 754
aoqi@0 755 private int processNamespaceAttributes(int item, boolean inscope){
aoqi@0 756 _stackTop.namespaceAIIsStart = _namespaceAIIsEnd;
aoqi@0 757 Set<String> prefixSet = inscope ? new HashSet<String>() : Collections.<String>emptySet();
aoqi@0 758
aoqi@0 759 while((item & TYPE_MASK) == T_NAMESPACE_ATTRIBUTE) {
aoqi@0 760 if (_namespaceAIIsEnd == _namespaceAIIsPrefix.length) {
aoqi@0 761 resizeNamespaceAttributes();
aoqi@0 762 }
aoqi@0 763
aoqi@0 764 switch(getNIIState(item)){
aoqi@0 765 case STATE_NAMESPACE_ATTRIBUTE:
aoqi@0 766 // Undeclaration of default namespace
aoqi@0 767 _namespaceAIIsPrefix[_namespaceAIIsEnd] =
aoqi@0 768 _namespaceAIIsNamespaceName[_namespaceAIIsEnd++] = "";
aoqi@0 769 if (inscope) {
aoqi@0 770 prefixSet.add("");
aoqi@0 771 }
aoqi@0 772 break;
aoqi@0 773 case STATE_NAMESPACE_ATTRIBUTE_P:
aoqi@0 774 // Undeclaration of namespace
aoqi@0 775 _namespaceAIIsPrefix[_namespaceAIIsEnd] = readStructureString();
aoqi@0 776 if (inscope) {
aoqi@0 777 prefixSet.add(_namespaceAIIsPrefix[_namespaceAIIsEnd]);
aoqi@0 778 }
aoqi@0 779 _namespaceAIIsNamespaceName[_namespaceAIIsEnd++] = "";
aoqi@0 780 break;
aoqi@0 781 case STATE_NAMESPACE_ATTRIBUTE_P_U:
aoqi@0 782 // Declaration with prefix
aoqi@0 783 _namespaceAIIsPrefix[_namespaceAIIsEnd] = readStructureString();
aoqi@0 784 if (inscope) {
aoqi@0 785 prefixSet.add(_namespaceAIIsPrefix[_namespaceAIIsEnd]);
aoqi@0 786 }
aoqi@0 787 _namespaceAIIsNamespaceName[_namespaceAIIsEnd++] = readStructureString();
aoqi@0 788 break;
aoqi@0 789 case STATE_NAMESPACE_ATTRIBUTE_U:
aoqi@0 790 // Default declaration
aoqi@0 791 _namespaceAIIsPrefix[_namespaceAIIsEnd] = "";
aoqi@0 792 if (inscope) {
aoqi@0 793 prefixSet.add("");
aoqi@0 794 }
aoqi@0 795 _namespaceAIIsNamespaceName[_namespaceAIIsEnd++] = readStructureString();
aoqi@0 796 break;
aoqi@0 797 }
aoqi@0 798 readStructure();
aoqi@0 799
aoqi@0 800 item = peekStructure();
aoqi@0 801 }
aoqi@0 802
aoqi@0 803 if (inscope) {
aoqi@0 804 for (Map.Entry<String, String> e : _buffer.getInscopeNamespaces().entrySet()) {
aoqi@0 805 String key = fixNull(e.getKey());
aoqi@0 806 // If the prefix is already written, do not write the prefix
aoqi@0 807 if (!prefixSet.contains(key)) {
aoqi@0 808 if (_namespaceAIIsEnd == _namespaceAIIsPrefix.length) {
aoqi@0 809 resizeNamespaceAttributes();
aoqi@0 810 }
aoqi@0 811 _namespaceAIIsPrefix[_namespaceAIIsEnd] = key;
aoqi@0 812 _namespaceAIIsNamespaceName[_namespaceAIIsEnd++] = e.getValue();
aoqi@0 813 }
aoqi@0 814 }
aoqi@0 815 }
aoqi@0 816 _stackTop.namespaceAIIsEnd = _namespaceAIIsEnd;
aoqi@0 817
aoqi@0 818 return item;
aoqi@0 819 }
aoqi@0 820
aoqi@0 821 private static String fixNull(String s) {
aoqi@0 822 if (s == null) return "";
aoqi@0 823 else return s;
aoqi@0 824 }
aoqi@0 825
aoqi@0 826 private void processAttributes(int item){
aoqi@0 827 do {
aoqi@0 828 switch(getAIIState(item)){
aoqi@0 829 case STATE_ATTRIBUTE_U_LN_QN: {
aoqi@0 830 final String uri = readStructureString();
aoqi@0 831 final String localName = readStructureString();
aoqi@0 832 final String prefix = getPrefixFromQName(readStructureString());
aoqi@0 833 _attributeCache.addAttributeWithPrefix(prefix, uri, localName, readStructureString(), readContentString());
aoqi@0 834 break;
aoqi@0 835 }
aoqi@0 836 case STATE_ATTRIBUTE_P_U_LN:
aoqi@0 837 _attributeCache.addAttributeWithPrefix(readStructureString(), readStructureString(), readStructureString(), readStructureString(), readContentString());
aoqi@0 838 break;
aoqi@0 839 case STATE_ATTRIBUTE_U_LN:
aoqi@0 840 // _attributeCache follows SAX convention
aoqi@0 841 _attributeCache.addAttributeWithPrefix("", readStructureString(), readStructureString(), readStructureString(), readContentString());
aoqi@0 842 break;
aoqi@0 843 case STATE_ATTRIBUTE_LN: {
aoqi@0 844 _attributeCache.addAttributeWithPrefix("", "", readStructureString(), readStructureString(), readContentString());
aoqi@0 845 break;
aoqi@0 846 }
aoqi@0 847 default :
aoqi@0 848 assert false : "Internal XSB Error: wrong attribute state, Item="+item;
aoqi@0 849 }
aoqi@0 850 readStructure();
aoqi@0 851
aoqi@0 852 item = peekStructure();
aoqi@0 853 } while((item & TYPE_MASK) == T_ATTRIBUTE);
aoqi@0 854 }
aoqi@0 855
aoqi@0 856 private void pushElementStack() {
aoqi@0 857 if (_depth == _stack.length) {
aoqi@0 858 // resize stack
aoqi@0 859 ElementStackEntry [] tmp = _stack;
aoqi@0 860 _stack = new ElementStackEntry[_stack.length * 3 /2 + 1];
aoqi@0 861 System.arraycopy(tmp, 0, _stack, 0, tmp.length);
aoqi@0 862 for (int i = tmp.length; i < _stack.length; i++){
aoqi@0 863 _stack[i] = new ElementStackEntry();
aoqi@0 864 }
aoqi@0 865 }
aoqi@0 866
aoqi@0 867 _stackTop = _stack[_depth++];
aoqi@0 868 }
aoqi@0 869
aoqi@0 870 private void popElementStack(int depth) {
aoqi@0 871 // _depth is checked outside this method
aoqi@0 872 _stackTop = _stack[depth - 1];
aoqi@0 873 // Move back the position of the namespace index
aoqi@0 874 _namespaceAIIsEnd = _stack[depth].namespaceAIIsStart;
aoqi@0 875 }
aoqi@0 876
aoqi@0 877 private final class ElementStackEntry {
aoqi@0 878 /**
aoqi@0 879 * Prefix.
aoqi@0 880 * Just like everywhere else in StAX, this can be null but can't be empty.
aoqi@0 881 */
aoqi@0 882 String prefix;
aoqi@0 883 /**
aoqi@0 884 * Namespace URI.
aoqi@0 885 * Just like everywhere else in StAX, this can be null but can't be empty.
aoqi@0 886 */
aoqi@0 887 String uri;
aoqi@0 888 String localName;
aoqi@0 889 QName qname;
aoqi@0 890
aoqi@0 891 // Start and end of namespace declarations
aoqi@0 892 // in namespace declaration arrays
aoqi@0 893 int namespaceAIIsStart;
aoqi@0 894 int namespaceAIIsEnd;
aoqi@0 895
aoqi@0 896 public void set(String prefix, String uri, String localName) {
aoqi@0 897 this.prefix = prefix;
aoqi@0 898 this.uri = uri;
aoqi@0 899 this.localName = localName;
aoqi@0 900 this.qname = null;
aoqi@0 901
aoqi@0 902 this.namespaceAIIsStart = this.namespaceAIIsEnd = StreamReaderBufferProcessor.this._namespaceAIIsEnd;
aoqi@0 903 }
aoqi@0 904
aoqi@0 905 public QName getQName() {
aoqi@0 906 if (qname == null) {
aoqi@0 907 qname = new QName(fixNull(uri), localName, fixNull(prefix));
aoqi@0 908 }
aoqi@0 909 return qname;
aoqi@0 910 }
aoqi@0 911
aoqi@0 912 private String fixNull(String s) {
aoqi@0 913 return (s == null) ? "" : s;
aoqi@0 914 }
aoqi@0 915 }
aoqi@0 916
aoqi@0 917 private final class InternalNamespaceContext implements NamespaceContextEx {
aoqi@0 918 @SuppressWarnings({"StringEquality"})
aoqi@0 919 public String getNamespaceURI(String prefix) {
aoqi@0 920 if (prefix == null) {
aoqi@0 921 throw new IllegalArgumentException("Prefix cannot be null");
aoqi@0 922 }
aoqi@0 923
aoqi@0 924 /*
aoqi@0 925 * If the buffer was created using string interning
aoqi@0 926 * intern the prefix and check for reference equality
aoqi@0 927 * rather than using String.equals();
aoqi@0 928 */
aoqi@0 929 if (_stringInterningFeature) {
aoqi@0 930 prefix = prefix.intern();
aoqi@0 931
aoqi@0 932 // Find the most recently declared prefix
aoqi@0 933 for (int i = _namespaceAIIsEnd - 1; i >=0; i--) {
aoqi@0 934 if (prefix == _namespaceAIIsPrefix[i]) {
aoqi@0 935 return _namespaceAIIsNamespaceName[i];
aoqi@0 936 }
aoqi@0 937 }
aoqi@0 938 } else {
aoqi@0 939 // Find the most recently declared prefix
aoqi@0 940 for (int i = _namespaceAIIsEnd - 1; i >=0; i--) {
aoqi@0 941 if (prefix.equals(_namespaceAIIsPrefix[i])) {
aoqi@0 942 return _namespaceAIIsNamespaceName[i];
aoqi@0 943 }
aoqi@0 944 }
aoqi@0 945 }
aoqi@0 946
aoqi@0 947 // Check for XML-based prefixes
aoqi@0 948 if (prefix.equals(XMLConstants.XML_NS_PREFIX)) {
aoqi@0 949 return XMLConstants.XML_NS_URI;
aoqi@0 950 } else if (prefix.equals(XMLConstants.XMLNS_ATTRIBUTE)) {
aoqi@0 951 return XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
aoqi@0 952 }
aoqi@0 953
aoqi@0 954 return null;
aoqi@0 955 }
aoqi@0 956
aoqi@0 957 public String getPrefix(String namespaceURI) {
aoqi@0 958 final Iterator i = getPrefixes(namespaceURI);
aoqi@0 959 if (i.hasNext()) {
aoqi@0 960 return (String)i.next();
aoqi@0 961 } else {
aoqi@0 962 return null;
aoqi@0 963 }
aoqi@0 964 }
aoqi@0 965
aoqi@0 966 public Iterator getPrefixes(final String namespaceURI) {
aoqi@0 967 if (namespaceURI == null){
aoqi@0 968 throw new IllegalArgumentException("NamespaceURI cannot be null");
aoqi@0 969 }
aoqi@0 970
aoqi@0 971 if (namespaceURI.equals(XMLConstants.XML_NS_URI)) {
aoqi@0 972 return Collections.singletonList(XMLConstants.XML_NS_PREFIX).iterator();
aoqi@0 973 } else if (namespaceURI.equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) {
aoqi@0 974 return Collections.singletonList(XMLConstants.XMLNS_ATTRIBUTE).iterator();
aoqi@0 975 }
aoqi@0 976
aoqi@0 977 return new Iterator() {
aoqi@0 978 private int i = _namespaceAIIsEnd - 1;
aoqi@0 979 private boolean requireFindNext = true;
aoqi@0 980 private String p;
aoqi@0 981
aoqi@0 982 private String findNext() {
aoqi@0 983 while(i >= 0) {
aoqi@0 984 // Find the most recently declared namespace
aoqi@0 985 if (namespaceURI.equals(_namespaceAIIsNamespaceName[i])) {
aoqi@0 986 // Find the most recently declared prefix of the namespace
aoqi@0 987 // and check if the prefix is in scope with that namespace
aoqi@0 988 if (getNamespaceURI(_namespaceAIIsPrefix[i]).equals(
aoqi@0 989 _namespaceAIIsNamespaceName[i])) {
aoqi@0 990 return p = _namespaceAIIsPrefix[i];
aoqi@0 991 }
aoqi@0 992 }
aoqi@0 993 i--;
aoqi@0 994 }
aoqi@0 995 return p = null;
aoqi@0 996 }
aoqi@0 997
aoqi@0 998 public boolean hasNext() {
aoqi@0 999 if (requireFindNext) {
aoqi@0 1000 findNext();
aoqi@0 1001 requireFindNext = false;
aoqi@0 1002 }
aoqi@0 1003 return (p != null);
aoqi@0 1004 }
aoqi@0 1005
aoqi@0 1006 public Object next() {
aoqi@0 1007 if (requireFindNext) {
aoqi@0 1008 findNext();
aoqi@0 1009 }
aoqi@0 1010 requireFindNext = true;
aoqi@0 1011
aoqi@0 1012 if (p == null) {
aoqi@0 1013 throw new NoSuchElementException();
aoqi@0 1014 }
aoqi@0 1015
aoqi@0 1016 return p;
aoqi@0 1017 }
aoqi@0 1018
aoqi@0 1019 public void remove() {
aoqi@0 1020 throw new UnsupportedOperationException();
aoqi@0 1021 }
aoqi@0 1022 };
aoqi@0 1023 }
aoqi@0 1024
aoqi@0 1025 private class BindingImpl implements NamespaceContextEx.Binding {
aoqi@0 1026 final String _prefix;
aoqi@0 1027 final String _namespaceURI;
aoqi@0 1028
aoqi@0 1029 BindingImpl(String prefix, String namespaceURI) {
aoqi@0 1030 _prefix = prefix;
aoqi@0 1031 _namespaceURI = namespaceURI;
aoqi@0 1032 }
aoqi@0 1033
aoqi@0 1034 public String getPrefix() {
aoqi@0 1035 return _prefix;
aoqi@0 1036 }
aoqi@0 1037
aoqi@0 1038 public String getNamespaceURI() {
aoqi@0 1039 return _namespaceURI;
aoqi@0 1040 }
aoqi@0 1041 }
aoqi@0 1042
aoqi@0 1043 public Iterator<NamespaceContextEx.Binding> iterator() {
aoqi@0 1044 return new Iterator<NamespaceContextEx.Binding>() {
aoqi@0 1045 private final int end = _namespaceAIIsEnd - 1;
aoqi@0 1046 private int current = end;
aoqi@0 1047 private boolean requireFindNext = true;
aoqi@0 1048 private NamespaceContextEx.Binding namespace;
aoqi@0 1049
aoqi@0 1050 private NamespaceContextEx.Binding findNext() {
aoqi@0 1051 while(current >= 0) {
aoqi@0 1052 final String prefix = _namespaceAIIsPrefix[current];
aoqi@0 1053
aoqi@0 1054 // Find if the current prefix occurs more recently
aoqi@0 1055 // If so then it is not in scope
aoqi@0 1056 int i = end;
aoqi@0 1057 for (;i > current; i--) {
aoqi@0 1058 if (prefix.equals(_namespaceAIIsPrefix[i])) {
aoqi@0 1059 break;
aoqi@0 1060 }
aoqi@0 1061 }
aoqi@0 1062 if (i == current--) {
aoqi@0 1063 // The current prefix is in-scope
aoqi@0 1064 return namespace = new BindingImpl(prefix, _namespaceAIIsNamespaceName[current]);
aoqi@0 1065 }
aoqi@0 1066 }
aoqi@0 1067 return namespace = null;
aoqi@0 1068 }
aoqi@0 1069
aoqi@0 1070 public boolean hasNext() {
aoqi@0 1071 if (requireFindNext) {
aoqi@0 1072 findNext();
aoqi@0 1073 requireFindNext = false;
aoqi@0 1074 }
aoqi@0 1075 return (namespace != null);
aoqi@0 1076 }
aoqi@0 1077
aoqi@0 1078 public NamespaceContextEx.Binding next() {
aoqi@0 1079 if (requireFindNext) {
aoqi@0 1080 findNext();
aoqi@0 1081 }
aoqi@0 1082 requireFindNext = true;
aoqi@0 1083
aoqi@0 1084 if (namespace == null) {
aoqi@0 1085 throw new NoSuchElementException();
aoqi@0 1086 }
aoqi@0 1087
aoqi@0 1088 return namespace;
aoqi@0 1089 }
aoqi@0 1090
aoqi@0 1091 public void remove() {
aoqi@0 1092 throw new UnsupportedOperationException();
aoqi@0 1093 }
aoqi@0 1094 };
aoqi@0 1095 }
aoqi@0 1096 }
aoqi@0 1097
aoqi@0 1098 private class DummyLocation implements Location {
aoqi@0 1099 public int getLineNumber() {
aoqi@0 1100 return -1;
aoqi@0 1101 }
aoqi@0 1102
aoqi@0 1103 public int getColumnNumber() {
aoqi@0 1104 return -1;
aoqi@0 1105 }
aoqi@0 1106
aoqi@0 1107 public int getCharacterOffset() {
aoqi@0 1108 return -1;
aoqi@0 1109 }
aoqi@0 1110
aoqi@0 1111 public String getPublicId() {
aoqi@0 1112 return null;
aoqi@0 1113 }
aoqi@0 1114
aoqi@0 1115 public String getSystemId() {
aoqi@0 1116 return _buffer.getSystemId();
aoqi@0 1117 }
aoqi@0 1118 }
aoqi@0 1119
aoqi@0 1120 private static String fixEmptyString(String s) {
aoqi@0 1121 // s must not be null, so no need to check for that. that would be bug.
aoqi@0 1122 if(s.length()==0) return null;
aoqi@0 1123 else return s;
aoqi@0 1124 }
aoqi@0 1125
aoqi@0 1126 }

mercurial