| 1 package net.sf.saxon.style; 2 3 import net.sf.saxon.Err; 4 import net.sf.saxon.PreparedStylesheet; 5 import net.sf.saxon.Configuration; 6 import net.sf.saxon.event.LocationProvider; 7 import net.sf.saxon.expr.*; 8 import net.sf.saxon.instruct.*; 9 import net.sf.saxon.om.*; 10 import net.sf.saxon.pattern.*; 11 import net.sf.saxon.sort.SortKeyDefinition; 12 import net.sf.saxon.trace.InstructionInfo; 13 import net.sf.saxon.trace.Location; 14 import net.sf.saxon.trans.DynamicError; 15 import net.sf.saxon.trans.SaxonErrorCode; 16 import net.sf.saxon.trans.StaticError; 17 import net.sf.saxon.trans.XPathException; 18 import net.sf.saxon.tree.ElementWithAttributes; 19 import net.sf.saxon.type.*; 20 import net.sf.saxon.value.*; 21 import org.xml.sax.Locator ; 22 23 import javax.xml.transform.SourceLocator ; 24 import javax.xml.transform.TransformerConfigurationException ; 25 import javax.xml.transform.TransformerException ; 26 import java.math.BigDecimal ; 27 import java.util.ArrayList ; 28 import java.util.Iterator ; 29 import java.util.List ; 30 import java.util.StringTokenizer ; 31 32 38 39 public abstract class StyleElement extends ElementWithAttributes 40 implements Locator , Container, InstructionInfo { 41 42 protected short[] extensionNamespaces = null; private short[] excludedNamespaces = null; protected BigDecimal version = null; 45 protected StaticContext staticContext = null; 46 protected StaticError validationError = null; 47 protected int reportingCircumstances = REPORT_ALWAYS; 48 protected String defaultXPathNamespace = null; 49 protected String defaultCollationName = null; 50 private int lineNumber; private boolean explaining = false; 53 private int objectNameCode = -1; 55 private XSLStylesheet containingStylesheet; 57 58 60 public static final int REPORT_ALWAYS = 1; 61 public static final int REPORT_UNLESS_FORWARDS_COMPATIBLE = 2; 62 public static final int REPORT_IF_INSTANTIATED = 3; 63 64 67 68 public StyleElement() { 69 } 70 71 public Executable getExecutable() { 72 return getPrincipalStylesheet().getExecutable(); 73 } 74 75 78 79 public LocationProvider getLocationProvider() { 80 return getExecutable().getLocationMap(); 81 } 82 83 87 88 public NamePool getTargetNamePool() { 89 return getPrincipalStylesheet().getTargetNamePool(); 90 } 91 92 97 98 public StaticContext getStaticContext() { 99 if (staticContext == null) { 100 staticContext = new ExpressionContext(this); 101 } 102 return staticContext; 103 } 104 105 public int getLineNumber() { 106 return lineNumber; 107 } 108 109 public void setLineNumber(int lineNumber) { 110 this.lineNumber = lineNumber; 111 } 112 113 116 117 protected boolean isExplaining() { 118 return explaining; 119 } 120 121 127 128 public void substituteFor(StyleElement temp) { 129 this.parent = temp.parent; 130 this.attributeList = temp.attributeList; 131 this.namespaceList = temp.namespaceList; 132 this.nameCode = temp.nameCode; 133 this.sequence = temp.sequence; 134 this.extensionNamespaces = temp.extensionNamespaces; 135 this.excludedNamespaces = temp.excludedNamespaces; 136 this.version = temp.version; 137 this.root = temp.root; 138 this.staticContext = temp.staticContext; 139 this.validationError = temp.validationError; 140 this.reportingCircumstances = temp.reportingCircumstances; 141 this.lineNumber = temp.lineNumber; 142 } 143 144 147 148 protected void setValidationError(TransformerException reason, 149 int circumstances) { 150 validationError = StaticError.makeStaticError(reason); 151 reportingCircumstances = circumstances; 152 } 153 154 157 158 public boolean isInstruction() { 159 return false; 160 } 161 162 171 172 protected ItemType getReturnedItemType() { 173 return AnyItemType.getInstance(); 174 } 175 176 181 182 protected ItemType getCommonChildItemType() { 183 ItemType t = NoNodeTest.getInstance(); 184 AxisIterator children = iterateAxis(Axis.CHILD); 185 while (true) { 186 NodeInfo next = (NodeInfo)children.next(); 187 if (next == null) { 188 return t; 189 } 190 if (next instanceof StyleElement) { 191 ItemType ret = ((StyleElement)next).getReturnedItemType(); 192 if (ret != null) { 193 t = Type.getCommonSuperType(t, ret); 194 } 195 } else { 196 t = Type.getCommonSuperType(t, NodeKindTest.TEXT); 197 } 198 if (t == AnyItemType.getInstance()) { 199 return t; } 201 } 202 } 203 204 208 209 public void markTailCalls() { 210 } 212 213 216 217 public boolean mayContainSequenceConstructor() { 218 return false; 219 } 220 221 225 226 public boolean mayContainFallback() { 227 return mayContainSequenceConstructor(); 228 } 229 230 233 234 public XSLStylesheet getContainingStylesheet() { 235 if (containingStylesheet == null) { 236 if (this instanceof XSLStylesheet) { 237 containingStylesheet = (XSLStylesheet)this; 238 } else { 239 containingStylesheet = ((StyleElement)getParent()).getContainingStylesheet(); 240 } 241 } 242 return containingStylesheet; 243 } 244 245 248 249 public int getPrecedence() { 250 return getContainingStylesheet().getPrecedence(); 251 } 252 253 263 264 277 288 289 public final int makeNameCode(String qname) 290 throws XPathException, NamespaceException { 291 292 NamePool namePool = getTargetNamePool(); 293 String [] parts; 294 try { 295 parts = Name.getQNameParts(qname); 296 } catch (QNameException err) { 297 StaticError e2 = new StaticError(err.getMessage()); 298 e2.setErrorCode("XTSE0020"); 299 throw e2; 300 } 301 String prefix = parts[0]; 302 if ("".equals(prefix)) { 303 return namePool.allocate(prefix, (short)0, qname); 304 305 } else { 306 307 String uri = getURIForPrefix(prefix, false); 308 if (uri == null) { 309 throw new NamespaceException(prefix); 310 } 311 if (NamespaceConstant.isReserved(uri)) { 312 StaticError err = new StaticError("Namespace prefix " + prefix + " refers to a reserved namespace"); 313 err.setErrorCode("XTSE0080"); 314 throw err; 315 } 316 return namePool.allocate(prefix, uri, parts[1]); 317 } 318 319 } 320 321 325 326 public SavedNamespaceContext makeNamespaceContext() { 327 return new SavedNamespaceContext(getInScopeNamespaceCodes(), getNamePool()); 328 } 329 330 333 334 public void processAllAttributes() throws XPathException { 335 staticContext = new ExpressionContext(this); 336 processAttributes(); 337 AxisIterator kids = iterateAxis(Axis.CHILD); 338 while (true) { 339 NodeInfo child = (NodeInfo)kids.next(); 340 if (child == null) { 341 return; 342 } 343 if (child instanceof StyleElement) { 344 ((StyleElement)child).processAllAttributes(); 345 if (((StyleElement)child).explaining) { 346 explaining = true; 349 } 350 } 351 } 352 } 353 354 358 359 public String getAttributeValue(String clarkName) { 360 int fp = getNamePool().allocateClarkName(clarkName); 361 return getAttributeValue(fp); 362 } 363 364 368 369 public final void processAttributes() throws XPathException { 370 try { 371 prepareAttributes(); 372 } catch (XPathException err) { 373 if (forwardsCompatibleModeIsEnabled()) { 374 setValidationError(err, REPORT_IF_INSTANTIATED); 375 } else { 376 compileError(err); 377 } 378 } 379 } 380 381 386 387 protected void checkUnknownAttribute(int nc) throws XPathException { 388 389 String attributeURI = getNamePool().getURI(nc); 390 String elementURI = getURI(); 391 String clarkName = getNamePool().getClarkName(nc); 392 393 if (clarkName.equals(StandardNames.SAXON_EXPLAIN)) { 394 explaining = "yes".equals(getAttributeValue(nc & 0xfffff)); 395 } 396 397 if (forwardsCompatibleModeIsEnabled()) { 398 return; 400 } 401 402 404 if (isInstruction() && 405 clarkName.startsWith('{' + NamespaceConstant.XSLT) && 406 !(elementURI.equals(NamespaceConstant.XSLT)) && 407 (clarkName.endsWith("}default-collation") || 408 clarkName.endsWith("}xpath-default-namespace") || 409 clarkName.endsWith("}extension-element-prefixes") || 410 clarkName.endsWith("}exclude-result-prefixes") || 411 clarkName.endsWith("}version") || 412 clarkName.endsWith("}use-when"))) { 413 return; 414 } 415 416 418 if (elementURI.equals(NamespaceConstant.XSLT) && 419 (clarkName == StandardNames.DEFAULT_COLLATION || 420 clarkName == StandardNames.XPATH_DEFAULT_NAMESPACE || 421 clarkName == StandardNames.EXTENSION_ELEMENT_PREFIXES || 422 clarkName == StandardNames.EXCLUDE_RESULT_PREFIXES || 423 clarkName == StandardNames.VERSION || 424 clarkName == StandardNames.USE_WHEN)) { 425 return; 426 } 427 428 if ("".equals(attributeURI) || NamespaceConstant.XSLT.equals(attributeURI)) { 429 compileError("Attribute " + Err.wrap(getNamePool().getDisplayName(nc), Err.ATTRIBUTE) + 430 " is not allowed on element " + Err.wrap(getDisplayName(), Err.ELEMENT), "XTSE0010"); 431 } 432 } 433 434 435 440 441 public abstract void prepareAttributes() throws XPathException; 442 443 447 448 protected StyleElement getLastChildInstruction() { 449 StyleElement last = null; 450 AxisIterator kids = iterateAxis(Axis.CHILD); 451 while (true) { 452 NodeInfo child = (NodeInfo)kids.next(); 453 if (child == null) { 454 return last; 455 } 456 if (child instanceof StyleElement) { 457 last = (StyleElement)child; 458 } else { 459 last = null; 460 } 461 } 462 } 463 464 467 468 public Expression makeExpression(String expression) 469 throws XPathException { 470 try { 471 Expression exp = ExpressionTool.make(expression, 472 staticContext, 473 0, Token.EOF, 474 getLineNumber()); 475 return exp; 476 } catch (XPathException err) { 477 err.setLocator(this); 478 if (!forwardsCompatibleModeIsEnabled()) { 479 compileError(err); 480 } else if (err.isTypeError()) { 481 compileError(err); 482 } 483 ErrorExpression erexp = new ErrorExpression(err); 484 erexp.setLocationId(allocateLocationId(getSystemId(), getLineNumber())); 485 erexp.setParentExpression(this); 486 return erexp; 487 } 488 } 489 490 493 494 public Pattern makePattern(String pattern) 495 throws XPathException { 496 try { 497 return Pattern.make(pattern, staticContext, getPrincipalStylesheet().getExecutable()); 498 } catch (XPathException err) { 499 if (forwardsCompatibleModeIsEnabled()) { 500 compileWarning("Invalid pattern, ignored because in forwards-compatibility mode. " + 501 err.getMessage(), err.getErrorCodeLocalPart()); 502 return new NodeTestPattern(NoNodeTest.getInstance()); 503 } else { 504 compileError(err); 505 return new NodeTestPattern(AnyNodeTest.getInstance()); 506 } 507 } 508 } 509 510 513 514 public Expression makeAttributeValueTemplate(String expression) 515 throws XPathException { 516 try { 517 return AttributeValueTemplate.make(expression, getLineNumber(), staticContext); 518 } catch (XPathException err) { 519 compileError(err); 520 return new StringValue(expression); 521 } 522 } 523 524 527 528 public SequenceType makeSequenceType(String sequenceType) 529 throws XPathException { 530 getStaticContext(); 531 try { 532 ExpressionParser parser = new ExpressionParser(); 533 return parser.parseSequenceType(sequenceType, staticContext); 534 } catch (XPathException err) { 535 compileError(err); 536 return SequenceType.ANY_SEQUENCE; 538 } 539 } 540 541 546 547 protected void processExtensionElementAttribute(String nc) 548 throws XPathException { 549 String ext = getAttributeValue(nc); 550 if (ext != null) { 551 int count = 0; 553 StringTokenizer st1 = new StringTokenizer (ext); 554 while (st1.hasMoreTokens()) { 555 st1.nextToken(); 556 count++; 557 } 558 extensionNamespaces = new short[count]; 559 count = 0; 560 StringTokenizer st2 = new StringTokenizer (ext); 561 while (st2.hasMoreTokens()) { 562 String s = st2.nextToken(); 563 if ("#default".equals(s)) { 564 s = ""; 565 } 566 try { 567 short uriCode = getURICodeForPrefix(s); 568 extensionNamespaces[count++] = uriCode; 569 } catch (NamespaceException err) { 570 extensionNamespaces = null; 571 compileError(err.getMessage(), "XT0280"); 572 } 573 } 574 } 575 } 576 577 582 583 protected void processExcludedNamespaces(String nc) 584 throws XPathException { 585 String ext = getAttributeValue(nc); 586 if (ext != null) { 587 if ("#all".equals(ext.trim())) { 588 int[] codes = getInScopeNamespaceCodes(); 589 excludedNamespaces = new short[codes.length]; 590 for (int i = 0; i < codes.length; i++) { 591 excludedNamespaces[i] = (short)(codes[i] & 0xffff); 592 } 593 } else { 594 int count = 0; 596 StringTokenizer st1 = new StringTokenizer (ext); 597 while (st1.hasMoreTokens()) { 598 st1.nextToken(); 599 count++; 600 } 601 excludedNamespaces = new short[count]; 602 count = 0; 603 StringTokenizer st2 = new StringTokenizer (ext); 604 while (st2.hasMoreTokens()) { 605 String s = st2.nextToken(); 606 if ("#default".equals(s)) { 607 s = ""; 608 } else if ("#all".equals(s)) { 609 compileError("In exclude-result-prefixes, cannot mix #all with other values", "XTSE0020"); 610 } 611 try { 612 short uriCode = getURICodeForPrefix(s); 613 excludedNamespaces[count++] = uriCode; 614 } catch (NamespaceException err) { 615 excludedNamespaces = null; 616 compileError(err.getMessage(), "XTSE0280"); 617 } 618 } 619 } 620 } 621 } 622 623 628 629 protected void processVersionAttribute(String nc) throws XPathException { 630 String v = getAttributeValue(nc); 631 if (v != null) { 632 AtomicValue val = DecimalValue.makeDecimalValue(v, true); 633 if (val instanceof ValidationErrorValue) { 634 compileError("The version attribute must be a decimal literal"); 635 } 636 version = ((DecimalValue)val).getValue(); 637 } 638 } 639 640 644 645 public BigDecimal getVersion() { 646 if (version == null) { 647 NodeInfo node = getParent(); 648 if (node instanceof StyleElement) { 649 version = ((StyleElement)node).getVersion(); 650 } else { 651 version = new BigDecimal ("2.0"); } 653 } 654 return version; 655 } 656 657 660 661 public boolean forwardsCompatibleModeIsEnabled() { 662 return getVersion().compareTo(BigDecimal.valueOf(2)) > 0; 663 } 664 665 668 669 public boolean backwardsCompatibleModeIsEnabled() { 670 return getVersion().compareTo(BigDecimal.valueOf(2)) < 0; 671 } 672 673 678 679 protected void processDefaultCollationAttribute(String nc) throws XPathException { 680 String v = getAttributeValue(nc); 681 if (v != null) { 682 StringTokenizer st = new StringTokenizer (v); 683 while (st.hasMoreTokens()) { 684 String uri = st.nextToken(); 685 if (uri.equals(NamespaceConstant.CODEPOINT_COLLATION_URI)) { 686 defaultCollationName = uri; 687 return; 688 } else if (uri.startsWith("http://saxon.sf.net/")) { 689 defaultCollationName = uri; 690 return; 691 } else if (getPrincipalStylesheet().getExecutable().getNamedCollation(uri) != null) { 692 defaultCollationName = uri; 693 return; 694 } 695 } 697 compileError("No recognized collation URI found in default-collation attribute", "XTSE0125"); 698 } 699 } 700 701 704 705 protected String getDefaultCollationName() { 706 StyleElement e = this; 707 while (true) { 708 if (e.defaultCollationName != null) { 709 return e.defaultCollationName; 710 } 711 NodeInfo p = e.getParent(); 712 if (!(p instanceof StyleElement)) { 713 break; 714 } 715 e = (StyleElement)p; 716 } 717 return getPrincipalStylesheet().getDefaultCollationName(); 718 } 719 720 728 729 protected boolean definesExtensionElement(short uriCode) { 730 if (extensionNamespaces == null) { 731 return false; 732 } 733 for (int i = 0; i < extensionNamespaces.length; i++) { 734 if (extensionNamespaces[i] == uriCode) { 735 return true; 736 } 737 } 738 return false; 739 } 740 741 747 748 public boolean isExtensionNamespace(short uriCode) { 749 NodeInfo anc = this; 750 while (anc instanceof StyleElement) { 751 if (((StyleElement)anc).definesExtensionElement(uriCode)) { 752 return true; 753 } 754 anc = anc.getParent(); 755 } 756 return false; 757 } 758 759 765 766 protected boolean definesExcludedNamespace(short uriCode) { 767 if (excludedNamespaces == null) { 768 return false; 769 } 770 for (int i = 0; i < excludedNamespaces.length; i++) { 771 if (excludedNamespaces[i] == uriCode) { 772 return true; 773 } 774 } 775 return false; 776 } 777 778 785 786 public boolean isExcludedNamespace(short uriCode) { 787 if (uriCode == NamespaceConstant.XSLT_CODE) { 788 return true; 789 } 790 if (isExtensionNamespace(uriCode)) { 791 return true; 792 } 793 NodeInfo anc = this; 794 while (anc instanceof StyleElement) { 795 if (((StyleElement)anc).definesExcludedNamespace(uriCode)) { 796 return true; 797 } 798 anc = anc.getParent(); 799 } 800 return false; 801 } 802 803 808 809 protected void processDefaultXPathNamespaceAttribute(String nc) throws TransformerConfigurationException { 810 String v = getAttributeValue(nc); 811 if (v != null) { 812 defaultXPathNamespace = v; 813 } 814 } 815 816 819 820 protected short getDefaultXPathNamespace() { 821 NodeInfo anc = this; 822 while (anc instanceof StyleElement) { 823 String x = ((StyleElement)anc).defaultXPathNamespace; 824 if (x != null) { 825 return getTargetNamePool().allocateCodeForURI(x); 826 } 827 anc = anc.getParent(); 828 } 829 return NamespaceConstant.NULL_CODE; 830 } 832 833 841 842 public SchemaType getSchemaType(String typeAtt) throws XPathException { 843 try { 844 String [] parts = Name.getQNameParts(typeAtt); 845 String lname = parts[1]; 846 String uri; 847 if ("".equals(parts[0])) { 848 short uricode = getDefaultXPathNamespace(); 850 uri = getTargetNamePool().getURIFromURICode(uricode); 851 nameCode = getTargetNamePool().allocate(parts[0], uricode, lname); 852 } else { 853 &nbs
|