1 package net.sf.saxon.pull; 2 3 import net.sf.saxon.event.PipelineConfiguration; 4 import net.sf.saxon.expr.XPathContext; 5 import net.sf.saxon.instruct.DocumentInstr; 6 import net.sf.saxon.instruct.ElementCreator; 7 import net.sf.saxon.instruct.ParentNodeConstructor; 8 import net.sf.saxon.om.*; 9 import net.sf.saxon.trans.XPathException; 10 import net.sf.saxon.trans.DynamicError; 11 import net.sf.saxon.type.Type; 12 import net.sf.saxon.value.AtomicValue; 13 import net.sf.saxon.Configuration; 14 15 import javax.xml.transform.SourceLocator ; 16 import javax.xml.transform.TransformerException ; 17 import java.util.ArrayList ; 18 import java.util.Stack ; 19 20 30 31 public class VirtualTreeWalker implements PullProvider, NamespaceDeclarations { 32 33 private PipelineConfiguration pipe; 34 private int currentEvent = START_OF_INPUT; 35 private int nameCode; 36 private int nextNameCode; 37 private ParentNodeConstructor instruction; 38 private XPathContext context; 39 private Stack constructorStack = new Stack (); 40 private Stack iteratorStack = new Stack (); 41 private PullProvider subordinateTreeWalker = null; 42 private boolean alreadyRead = false; 47 private boolean allowAttributes = false; 48 49 private int stripDepth = -1; 50 54 private AttributeCollectionImpl attributes; 55 private boolean foundAttributes; 56 private int[] activeNamespaces; 57 private ArrayList additionalNamespaces = new ArrayList (10); 59 66 67 public VirtualTreeWalker(ParentNodeConstructor instruction, XPathContext context) { 68 this.instruction = instruction; 69 this.context = context; 70 } 71 72 76 77 public void setPipelineConfiguration(PipelineConfiguration pipe) { 78 this.pipe = pipe; 79 } 80 81 84 85 public PipelineConfiguration getPipelineConfiguration() { 86 return pipe; 87 } 88 89 92 93 public NamePool getNamePool() { 94 return pipe.getConfiguration().getNamePool(); 95 } 96 97 103 104 public int next() throws XPathException { 105 106 try { 107 108 111 if (subordinateTreeWalker != null) { 112 currentEvent = subordinateTreeWalker.next(); 113 if (currentEvent == END_OF_INPUT) { 114 subordinateTreeWalker = null; 115 return next(); 116 } 117 return currentEvent; 118 } 119 120 122 if (currentEvent == START_OF_INPUT) { 123 constructorStack.push(instruction); 124 if (stripDepth < 0 && instruction.getValidationAction() == Validation.STRIP) { 125 stripDepth = constructorStack.size(); 126 } 127 SequenceIterator content = instruction.getContentExpression().iterate(context); 128 iteratorStack.push(content); 129 if (instruction instanceof DocumentInstr) { 130 currentEvent = START_DOCUMENT; 131 nameCode = -1; 132 } else { 133 currentEvent = START_ELEMENT; 134 nameCode = ((ElementCreator)instruction).getNameCode(context); 135 allowAttributes = true; 136 processAttributesAndNamespaces((ElementCreator)instruction, content); 138 allowAttributes = false; 140 alreadyRead = true; 141 } 142 return currentEvent; 143 } 144 145 if (iteratorStack.isEmpty()) { 146 if (currentEvent == START_DOCUMENT || currentEvent == START_ELEMENT) { 148 SequenceIterator iter = instruction.getContentExpression().iterate(context); 150 constructorStack.push(instruction); 151 if (stripDepth < 0 && instruction.getValidationAction() == Validation.STRIP) { 152 stripDepth = constructorStack.size(); 153 } 154 iteratorStack.push(iter); 155 } else if (currentEvent == END_DOCUMENT || currentEvent == END_ELEMENT) { 156 currentEvent = END_OF_INPUT; 158 return currentEvent; 159 } else { 160 currentEvent = 162 ((instruction instanceof DocumentInstr) ? END_DOCUMENT : END_ELEMENT); 163 return currentEvent; 164 } 165 } 166 167 169 SequenceIterator iterator = ((SequenceIterator)iteratorStack.peek()); 170 if (alreadyRead) { 171 Item item = iterator.current(); 172 alreadyRead = false; 173 nameCode = nextNameCode; 174 return processItem(iterator, item); 175 } else { 176 return processItem(iterator, iterator.next()); 177 } 178 } catch (XPathException e) { 179 if (!e.hasBeenReported()) { 181 try { 182 context.getController().getErrorListener().fatalError(e); 183 } catch (TransformerException e2) { 184 } 186 } 187 throw e; 188 } 189 } 190 191 private FastStringBuffer textNodeBuffer = new FastStringBuffer(100); 192 193 201 202 private int processItem(SequenceIterator iterator, Item item) throws XPathException { 203 if (item == null) { 204 if (stripDepth == constructorStack.size()) { 206 stripDepth = -1; 207 } 208 ParentNodeConstructor inst = (ParentNodeConstructor)constructorStack.pop(); 209 if (inst instanceof DocumentInstr) { 210 iteratorStack.pop(); 211 if (iteratorStack.isEmpty()) { 212 currentEvent = END_DOCUMENT; 213 nameCode = -1; 214 return currentEvent; 215 } 216 return next(); 218 } else { 219 currentEvent = END_ELEMENT; 220 nameCode = -1; 221 iteratorStack.pop(); 222 return currentEvent; 223 } 224 225 226 } else if (item instanceof UnconstructedParent) { 227 UnconstructedParent parent = (UnconstructedParent)item; 229 ParentNodeConstructor inst = parent.getInstruction(); 230 231 constructorStack.push(inst); 232 if (stripDepth < 0 && inst.getValidationAction() == Validation.STRIP) { 233 stripDepth = constructorStack.size(); 234 } 235 SequenceIterator content = inst.getContentExpression().iterate(parent.getXPathContext()); 236 if (inst instanceof DocumentInstr) { 237 iteratorStack.push(content); 238 return next(); 240 } else { 241 currentEvent = START_ELEMENT; 242 nameCode = ((UnconstructedElement)item).getNameCode(); 243 processAttributesAndNamespaces((ElementCreator)inst, content); 244 alreadyRead = true; 245 iteratorStack.push(content); 246 return currentEvent; 247 } 248 249 } else if (item instanceof AtomicValue) { 250 textNodeBuffer.setLength(0); 251 textNodeBuffer.append(item.getStringValueCS()); 252 while (true) { 253 Item next = iterator.next(); 254 if (next instanceof AtomicValue) { 255 textNodeBuffer.append(' '); 256 textNodeBuffer.append(next.getStringValueCS()); 257 continue; 258 } else { 259 currentEvent = TEXT; 260 nameCode = -1; 261 alreadyRead = true; 262 return currentEvent; 263 } 264 } 265 266 } else { 267 nameCode = ((NodeInfo)item).getNameCode(); 268 switch (((NodeInfo)item).getNodeKind()) { 269 case Type.TEXT: 270 currentEvent = TEXT; 271 textNodeBuffer.setLength(0); 272 textNodeBuffer.append(item.getStringValueCS()); 273 return currentEvent; 275 276 case Type.COMMENT: 277 currentEvent = COMMENT; 278 return currentEvent; 279 280 case Type.PROCESSING_INSTRUCTION: 281 currentEvent = PROCESSING_INSTRUCTION; 282 return currentEvent; 283 284 case Type.ATTRIBUTE: 285 if (!allowAttributes) { 286 DynamicError de; 287 if (constructorStack.peek() instanceof DocumentInstr) { 288 de = new DynamicError( 289 "Attributes cannot be attached to a document node"); 290 if (context.getController().getExecutable().getHostLanguage() == Configuration.XQUERY) { 291 de.setErrorCode("XQTY0004"); 292 } else { 293 de.setErrorCode("XTDE0420"); 294 } 295 } else { 296 de = new DynamicError( 297 "Attributes in the content of an element must come before the child nodes"); 298 if (context.getController().getExecutable().getHostLanguage() == Configuration.XQUERY) { 299 de.setErrorCode("XQDY0024"); 300 } else { 301 de.setErrorCode("XTDE0410"); 302 } 303 } 304 de.setXPathContext(context); 305 de.setLocator(getSourceLocator()); 306 throw de; 307 } 308 currentEvent = ATTRIBUTE; 309 return currentEvent; 310 311 case Type.NAMESPACE: 312 if (!allowAttributes) { 313 DynamicError de = new DynamicError( 314 "Namespace nodes in the content of an element must come before the child nodes"); 315 de.setErrorCode("XTDE0410"); 316 de.setXPathContext(context); 317 de.setLocator(getSourceLocator()); 318 throw de; 319 } 320 currentEvent = NAMESPACE; 321 return currentEvent; 322 323 case Type.ELEMENT: 324 subordinateTreeWalker = TreeWalker.makeTreeWalker((NodeInfo)item); 325 subordinateTreeWalker.setPipelineConfiguration(pipe); 326 currentEvent = subordinateTreeWalker.next(); 327 nameCode = subordinateTreeWalker.getNameCode(); 328 return currentEvent; 329 330 case Type.DOCUMENT: 331 subordinateTreeWalker = TreeWalker.makeTreeWalker((NodeInfo)item); 332 subordinateTreeWalker.setPipelineConfiguration(pipe); 333 subordinateTreeWalker = new DocumentEventIgnorer(subordinateTreeWalker); 334 subordinateTreeWalker.setPipelineConfiguration(pipe); 335 currentEvent = subordinateTreeWalker.next(); 336 nameCode = -1; 337 return currentEvent; 338 339 default: 340 throw new IllegalStateException (); 341 342 } 343 } 344 } 345 346 356 private void processAttributesAndNamespaces(ElementCreator inst, SequenceIterator content) throws XPathException { 357 foundAttributes = false; 358 additionalNamespaces.clear(); 359 activeNamespaces = inst.getActiveNamespaces(); 360 if (activeNamespaces == null) { 361 activeNamespaces = EMPTY_INT_ARRAY; 362 } 363 boolean preserve = (stripDepth<0); 364 while (true) { 365 Item next = content.next(); 366 if (next == null) { 367 break; 368 } else if (next instanceof NodeInfo) { 369 NodeInfo node = (NodeInfo)next; 370 int kind = node.getNodeKind(); 371 if (kind == Type.ATTRIBUTE) { 372 if (!foundAttributes) { 373 if (attributes == null) { 374 attributes = new AttributeCollectionImpl(context.getController().getNamePool()); 375 } 376 attributes.clear(); 377 foundAttributes = true; 378 } 379 int index = attributes.getIndexByFingerprint(node.getFingerprint()); 380 if (index >= 0) { 381 if (context.getController().getExecutable().getHostLanguage() == Configuration.XSLT) { 383 attributes.setAttribute(index, 384 node.getNameCode(), 385 preserve ? node.getTypeAnnotation() : -1, 386 node.getStringValue(), 0, 0); 387 } else { 388 DynamicError de = new DynamicError( 389 "The attributes of an element must have distinct names"); 390 de.setErrorCode("XQDY0025"); 391 de.setXPathContext(context); 392 de.setLocator(getSourceLocator()); 393 throw de; 394 } 395 } else { 396 attributes.addAttribute( 397 node.getNameCode(), 398 preserve ? node.getTypeAnnotation() : -1, 399 node.getStringValue(), 400 0, 0); 401 } 402 } else if (kind == Type.NAMESPACE) { 403 additionalNamespaces.add(node); 404 } else { 405 nextNameCode = ((NodeInfo)next).getNameCode(); 406 break; 407 } 408 } else { 409 break; 410 } 411 } 412 } 413 414 421 422 public int current() { 423 return currentEvent; 424 } 425 426 440 441 public AttributeCollection getAttributes() throws XPathException { 442 if (subordinateTreeWalker != null) { 443 return subordinateTreeWalker.getAttributes(); 444 } else { 445 if (foundAttributes) { 446 return attributes; 447 } else { 448 return AttributeCollectionImpl.EMPTY_ATTRIBUTE_COLLECTION; 449 } 450 } 451 } 452 453 472 473 public NamespaceDeclarations getNamespaceDeclarations() throws XPathException { 474 if (subordinateTreeWalker != null) { 475 return subordinateTreeWalker.getNamespaceDeclarations(); 476 } else { 477 return this; 478 } 479 } 480 481 489 490 public int skipToMatchingEnd() throws XPathException { 491 if (currentEvent != START_DOCUMENT && currentEvent != START_ELEMENT) { 492 throw new IllegalStateException (); 493 } 494 if (subordinateTreeWalker != null) { 495 return subordinateTreeWalker.skipToMatchingEnd(); 496 } else { 497 SequenceIterator content = (SequenceIterator)iteratorStack.peek(); 498 if (alreadyRead) { 499 alreadyRead = false; 500 } 501 while (true) { 502 Item next = content.next(); 503 if (next == null) { 504 break; 505 } 506 } 507 return (currentEvent == START_DOCUMENT ? END_DOCUMENT : END_ELEMENT); 508 } 509 } 510 511 518 519 public void close() { 520 if (subordinateTreeWalker != null) { 521 subordinateTreeWalker.close(); 522 } else { 523 } 525 } 526 527 530 531 public void setNameCode(int nameCode) { 532 this.nameCode = nameCode; 533 } 534 535 547 548 public int getNameCode() { 549 if (subordinateTreeWalker != null) { 550 return subordinateTreeWalker.getNameCode(); 551 } 552 return nameCode; 553 } 554 555 568 569 public int getFingerprint() { 570 int nc = getNameCode(); 571 if (nc == -1) { 572 return -1; 573 } else { 574 return nc & NamePool.FP_MASK; 575 } 576 } 577 578 592 593 public CharSequence getStringValue() throws XPathException { 594 if (subordinateTreeWalker != null) { 595 return subordinateTreeWalker.getStringValue(); 596 } else if (currentEvent == TEXT) { 597 return textNodeBuffer; 598 } else if (currentEvent != START_ELEMENT && currentEvent != START_DOCUMENT) { 599 SequenceIterator content = (SequenceIterator)iteratorStack.peek(); 600 if (content.current() == null) { 601 return ""; 602 } 603 return content.current().getStringValue(); 604 } else { 605 FastStringBuffer sb = new FastStringBuffer(100); 606 SequenceIterator content = (SequenceIterator)iteratorStack.peek(); 607 if (alreadyRead) { 608 if (content.current() == null) { 609 return ""; 610 } 611 processText(content.current(), sb); 612 alreadyRead = false; 613 } 614 while (true) { 615 Item next = content.next(); 616 if (next == null) { 617 break; 618 } 619 processText(next, sb); 620 } 621 return sb; 622 } 623 } 624 625 631 632 private void processText(Item item, FastStringBuffer sb) { 633 if (item instanceof UnconstructedParent) { 634 sb.append(item.getStringValueCS()); 635 } else if (item instanceof AtomicValue) { 636 sb.append(item.getStringValueCS()); 637 } else { 638 NodeInfo node = (NodeInfo)item; 639 switch (node.getNodeKind()) { 640 case Type.DOCUMENT: 641 case Type.ELEMENT: 642 case Type.TEXT: 643 sb.append(node.getStringValueCS()); 644 default: 645 } 647 } 648 } 649 650 655 656 public AtomicValue getAtomicValue() { 657 throw new IllegalStateException (); 658 } 659 660 668 669 public int getTypeAnnotation() { 670 if (subordinateTreeWalker != null && stripDepth < 0) { 671 return subordinateTreeWalker.getTypeAnnotation(); 672 } else { 673 return -1; 674 } 675 } 676 677 684 685 public SourceLocator getSourceLocator() { 686 return instruction; 687 } 688 689 692 693 public int getLength() { 694 return activeNamespaces.length + additionalNamespaces.size(); 695 } 696 697 706 707 public String getPrefix(int index) { 708 if (index < activeNamespaces.length) { 709 return getNamePool().getPrefixFromNamespaceCode(activeNamespaces[index]); 710 } else { 711 return ((NodeInfo)additionalNamespaces.get(index - activeNamespaces.length)).getLocalPart(); 712 } 713 } 714 715 724 725 public String getURI(int index) { 726 if (index < activeNamespaces.length) { 727 return getNamePool().getURIFromNamespaceCode(activeNamespaces[index]); 728 } else { 729 return ((NodeInfo)additionalNamespaces.get(index - activeNamespaces.length)).getStringValue(); 730 } 731 } 732 733 746 747 public int getNamespaceCode(int index) { 748 if (index < activeNamespaces.length) { 749 return activeNamespaces[index]; 750 } else { 751 return getNamePool().allocateNamespaceCode(getPrefix(index), getURI(index)); 752 } 753 } 754 755 764 765 767 public int[] getNamespaceCodes(int[] buffer) { 768 if (buffer.length < getLength()) { 769 buffer = new int[getLength()]; 770 } else { 771 buffer[getLength()] = -1; 772 } 773 for (int i=0; i<getLength(); i++) { 774 buffer[i] = getNamespaceCode(i); 775 } 776 return buffer; 777 } 778 779 private static final int[] EMPTY_INT_ARRAY = new int[0]; 780 } 781 782 800 | Popular Tags |