001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 /* 019 * $Id: ElemLiteralResult.java 1225375 2011-12-28 23:03:43Z mrglavas $ 020 */ 021 package org.apache.xalan.templates; 022 023 import java.util.ArrayList; 024 import java.util.Iterator; 025 import java.util.List; 026 027 import javax.xml.transform.TransformerException; 028 029 import org.apache.xalan.res.XSLMessages; 030 import org.apache.xalan.res.XSLTErrorResources; 031 import org.apache.xalan.transformer.TransformerImpl; 032 import org.apache.xml.serializer.SerializationHandler; 033 import org.apache.xml.utils.StringVector; 034 import org.apache.xpath.XPathContext; 035 import org.w3c.dom.Attr; 036 import org.w3c.dom.DOMException; 037 import org.w3c.dom.Document; 038 import org.w3c.dom.Element; 039 import org.w3c.dom.NamedNodeMap; 040 import org.w3c.dom.Node; 041 import org.w3c.dom.NodeList; 042 import org.w3c.dom.TypeInfo; 043 import org.w3c.dom.UserDataHandler; 044 import org.xml.sax.SAXException; 045 046 /** 047 * Implement a Literal Result Element. 048 * @see <a href="http://www.w3.org/TR/xslt#literal-result-element">literal-result-element in XSLT Specification</a> 049 * @xsl.usage advanced 050 */ 051 public class ElemLiteralResult extends ElemUse 052 { 053 static final long serialVersionUID = -8703409074421657260L; 054 055 /** The return value as Empty String. */ 056 private static final String EMPTYSTRING = ""; 057 058 /** 059 * Tells if this element represents a root element 060 * that is also the stylesheet element. 061 * TODO: This should be a derived class. 062 * @serial 063 */ 064 private boolean isLiteralResultAsStylesheet = false; 065 066 /** 067 * Set whether this element represents a root element 068 * that is also the stylesheet element. 069 * 070 * 071 * @param b boolean flag indicating whether this element 072 * represents a root element that is also the stylesheet element. 073 */ 074 public void setIsLiteralResultAsStylesheet(boolean b) 075 { 076 isLiteralResultAsStylesheet = b; 077 } 078 079 /** 080 * Return whether this element represents a root element 081 * that is also the stylesheet element. 082 * 083 * 084 * @return boolean flag indicating whether this element 085 * represents a root element that is also the stylesheet element. 086 */ 087 public boolean getIsLiteralResultAsStylesheet() 088 { 089 return isLiteralResultAsStylesheet; 090 } 091 092 /** 093 * This function is called after everything else has been 094 * recomposed, and allows the template to set remaining 095 * values that may be based on some other property that 096 * depends on recomposition. 097 */ 098 public void compose(StylesheetRoot sroot) throws TransformerException 099 { 100 super.compose(sroot); 101 StylesheetRoot.ComposeState cstate = sroot.getComposeState(); 102 java.util.Vector vnames = cstate.getVariableNames(); 103 if (null != m_avts) 104 { 105 int nAttrs = m_avts.size(); 106 107 for (int i = (nAttrs - 1); i >= 0; i--) 108 { 109 AVT avt = (AVT) m_avts.get(i); 110 avt.fixupVariables(vnames, cstate.getGlobalsSize()); 111 } 112 } 113 } 114 115 /** 116 * The created element node will have the attribute nodes 117 * that were present on the element node in the stylesheet tree, 118 * other than attributes with names in the XSLT namespace. 119 * @serial 120 */ 121 private List m_avts = null; 122 123 /** List of attributes with the XSLT namespace. 124 * @serial */ 125 private List m_xslAttr = null; 126 127 /** 128 * Set a literal result attribute (AVTs only). 129 * 130 * @param avt literal result attribute to add (AVT only) 131 */ 132 public void addLiteralResultAttribute(AVT avt) 133 { 134 135 if (null == m_avts) 136 m_avts = new ArrayList(); 137 138 m_avts.add(avt); 139 } 140 141 /** 142 * Set a literal result attribute (used for xsl attributes). 143 * 144 * @param att literal result attribute to add 145 */ 146 public void addLiteralResultAttribute(String att) 147 { 148 149 if (null == m_xslAttr) 150 m_xslAttr = new ArrayList(); 151 152 m_xslAttr.add(att); 153 } 154 155 /** 156 * Set the "xml:space" attribute. 157 * A text node is preserved if an ancestor element of the text node 158 * has an xml:space attribute with a value of preserve, and 159 * no closer ancestor element has xml:space with a value of default. 160 * @see <a href="http://www.w3.org/TR/xslt#strip">strip in XSLT Specification</a> 161 * @see <a href="http://www.w3.org/TR/xslt#section-Creating-Text">section-Creating-Text in XSLT Specification</a> 162 * 163 * @param avt Enumerated value, either Constants.ATTRVAL_PRESERVE 164 * or Constants.ATTRVAL_STRIP. 165 */ 166 public void setXmlSpace(AVT avt) 167 { 168 // This function is a bit-o-hack, I guess... 169 addLiteralResultAttribute(avt); 170 String val = avt.getSimpleString(); 171 if(val.equals("default")) 172 { 173 super.setXmlSpace(Constants.ATTRVAL_STRIP); 174 } 175 else if(val.equals("preserve")) 176 { 177 super.setXmlSpace(Constants.ATTRVAL_PRESERVE); 178 } 179 // else maybe it's a real AVT, so we can't resolve it at this time. 180 } 181 182 /** 183 * Get a literal result attribute by name. 184 * 185 * @param namespaceURI Namespace URI of attribute node to get 186 * @param localName Local part of qualified name of attribute node to get 187 * 188 * @return literal result attribute (AVT) 189 */ 190 public AVT getLiteralResultAttributeNS(String namespaceURI, String localName) 191 { 192 193 if (null != m_avts) 194 { 195 int nAttrs = m_avts.size(); 196 197 for (int i = (nAttrs - 1); i >= 0; i--) 198 { 199 AVT avt = (AVT) m_avts.get(i); 200 201 if (avt.getName().equals(localName) && 202 avt.getURI().equals(namespaceURI)) 203 { 204 return avt; 205 } 206 } // end for 207 } 208 209 return null; 210 } 211 212 /** 213 * Return the raw value of the attribute. 214 * 215 * @param namespaceURI Namespace URI of attribute node to get 216 * @param localName Local part of qualified name of attribute node to get 217 * 218 * @return The Attr value as a string, or the empty string if that attribute 219 * does not have a specified or default value 220 */ 221 public String getAttributeNS(String namespaceURI, String localName) 222 { 223 224 AVT avt = getLiteralResultAttributeNS(namespaceURI, localName); 225 226 if ((null != avt)) 227 { 228 return avt.getSimpleString(); 229 } 230 231 return EMPTYSTRING; 232 } 233 234 /** 235 * Get a literal result attribute by name. The name is namespaceURI:localname 236 * if namespace is not null. 237 * 238 * @param name Name of literal result attribute to get 239 * 240 * @return literal result attribute (AVT) 241 */ 242 public AVT getLiteralResultAttribute(String name) 243 { 244 245 if (null != m_avts) 246 { 247 int nAttrs = m_avts.size(); 248 String namespace = null; 249 for (int i = (nAttrs - 1); i >= 0; i--) 250 { 251 AVT avt = (AVT) m_avts.get(i); 252 namespace = avt.getURI(); 253 254 if ((namespace != null && (namespace.length() != 0) && (namespace 255 +":"+avt.getName()).equals(name))|| ((namespace == null || 256 namespace.length() == 0)&& avt.getRawName().equals(name))) 257 { 258 return avt; 259 } 260 } // end for 261 } 262 263 return null; 264 } 265 266 /** 267 * Return the raw value of the attribute. 268 * 269 * @param namespaceURI:localName or localName if the namespaceURI is null of 270 * the attribute to get 271 * 272 * @return The Attr value as a string, or the empty string if that attribute 273 * does not have a specified or default value 274 */ 275 public String getAttribute(String rawName) 276 { 277 278 AVT avt = getLiteralResultAttribute(rawName); 279 280 if ((null != avt)) 281 { 282 return avt.getSimpleString(); 283 } 284 285 return EMPTYSTRING; 286 } 287 288 /** 289 * Get whether or not the passed URL is flagged by 290 * the "extension-element-prefixes" or "exclude-result-prefixes" 291 * properties. 292 * @see <a href="http://www.w3.org/TR/xslt#extension-element">extension-element in XSLT Specification</a> 293 * 294 * @param prefix non-null reference to prefix that might be excluded.(not currently used) 295 * @param uri reference to namespace that prefix maps to 296 * 297 * @return true if the prefix should normally be excluded. 298 */ 299 public boolean containsExcludeResultPrefix(String prefix, String uri) 300 { 301 if (uri == null || 302 (null == m_excludeResultPrefixes && 303 null == m_ExtensionElementURIs) 304 ) 305 return super.containsExcludeResultPrefix(prefix, uri); 306 307 if (prefix.length() == 0) 308 prefix = Constants.ATTRVAL_DEFAULT_PREFIX; 309 310 // This loop is ok here because this code only runs during 311 // stylesheet compile time. 312 if(m_excludeResultPrefixes!=null) 313 for (int i =0; i< m_excludeResultPrefixes.size(); i++) 314 { 315 if (uri.equals(getNamespaceForPrefix(m_excludeResultPrefixes.elementAt(i)))) 316 return true; 317 } 318 319 // JJK Bugzilla 1133: Also check locally-scoped extensions 320 if(m_ExtensionElementURIs!=null && m_ExtensionElementURIs.contains(uri)) 321 return true; 322 323 return super.containsExcludeResultPrefix(prefix, uri); 324 } 325 326 /** 327 * Augment resolvePrefixTables, resolving the namespace aliases once 328 * the superclass has resolved the tables. 329 * 330 * @throws TransformerException 331 */ 332 public void resolvePrefixTables() throws TransformerException 333 { 334 335 super.resolvePrefixTables(); 336 337 StylesheetRoot stylesheet = getStylesheetRoot(); 338 339 if ((null != m_namespace) && (m_namespace.length() > 0)) 340 { 341 NamespaceAlias nsa = stylesheet.getNamespaceAliasComposed(m_namespace); 342 343 if (null != nsa) 344 { 345 m_namespace = nsa.getResultNamespace(); 346 347 // String resultPrefix = nsa.getResultPrefix(); 348 String resultPrefix = nsa.getStylesheetPrefix(); // As per xsl WG, Mike Kay 349 350 if ((null != resultPrefix) && (resultPrefix.length() > 0)) 351 m_rawName = resultPrefix + ":" + m_localName; 352 else 353 m_rawName = m_localName; 354 } 355 } 356 357 if (null != m_avts) 358 { 359 int n = m_avts.size(); 360 361 for (int i = 0; i < n; i++) 362 { 363 AVT avt = (AVT) m_avts.get(i); 364 365 // Should this stuff be a method on AVT? 366 String ns = avt.getURI(); 367 368 if ((null != ns) && (ns.length() > 0)) 369 { 370 NamespaceAlias nsa = 371 stylesheet.getNamespaceAliasComposed(m_namespace); // %REVIEW% ns? 372 373 if (null != nsa) 374 { 375 String namespace = nsa.getResultNamespace(); 376 377 // String resultPrefix = nsa.getResultPrefix(); 378 String resultPrefix = nsa.getStylesheetPrefix(); // As per XSL WG 379 String rawName = avt.getName(); 380 381 if ((null != resultPrefix) && (resultPrefix.length() > 0)) 382 rawName = resultPrefix + ":" + rawName; 383 384 avt.setURI(namespace); 385 avt.setRawName(rawName); 386 } 387 } 388 } 389 } 390 } 391 392 /** 393 * Return whether we need to check namespace prefixes 394 * against the exclude result prefixes or extensions lists. 395 * Note that this will create a new prefix table if one 396 * has not been created already. 397 * 398 * NEEDSDOC ($objectName$) @return 399 */ 400 boolean needToCheckExclude() 401 { 402 if (null == m_excludeResultPrefixes && null == getPrefixTable() 403 && m_ExtensionElementURIs==null // JJK Bugzilla 1133 404 ) 405 return false; 406 else 407 { 408 409 // Create a new prefix table if one has not already been created. 410 if (null == getPrefixTable()) 411 setPrefixTable(new java.util.ArrayList()); 412 413 return true; 414 } 415 } 416 417 /** 418 * The namespace of the element to be created. 419 * @serial 420 */ 421 private String m_namespace; 422 423 /** 424 * Set the namespace URI of the result element to be created. 425 * Note that after resolvePrefixTables has been called, this will 426 * return the aliased result namespace, not the original stylesheet 427 * namespace. 428 * 429 * @param ns The Namespace URI, or the empty string if the 430 * element has no Namespace URI. 431 */ 432 public void setNamespace(String ns) 433 { 434 if(null == ns) // defensive, shouldn't have to do this. 435 ns = ""; 436 m_namespace = ns; 437 } 438 439 /** 440 * Get the original namespace of the Literal Result Element. 441 * 442 * %REVIEW% Why isn't this overriding the getNamespaceURI method 443 * rather than introducing a new one? 444 * 445 * @return The Namespace URI, or the empty string if the 446 * element has no Namespace URI. 447 */ 448 public String getNamespace() 449 { 450 return m_namespace; 451 } 452 453 /** 454 * The local name of the element to be created. 455 * @serial 456 */ 457 private String m_localName; 458 459 /** 460 * Set the local name of the LRE. 461 * 462 * @param localName The local name (without prefix) of the result element 463 * to be created. 464 */ 465 public void setLocalName(String localName) 466 { 467 m_localName = localName; 468 } 469 470 /** 471 * Get the local name of the Literal Result Element. 472 * Note that after resolvePrefixTables has been called, this will 473 * return the aliased name prefix, not the original stylesheet 474 * namespace prefix. 475 * 476 * @return The local name (without prefix) of the result element 477 * to be created. 478 */ 479 public String getLocalName() 480 { 481 return m_localName; 482 } 483 484 /** 485 * The raw name of the element to be created. 486 * @serial 487 */ 488 private String m_rawName; 489 490 /** 491 * Set the raw name of the LRE. 492 * 493 * @param rawName The qualified name (with prefix), or the 494 * empty string if qualified names are not available. 495 */ 496 public void setRawName(String rawName) 497 { 498 m_rawName = rawName; 499 } 500 501 /** 502 * Get the raw name of the Literal Result Element. 503 * 504 * @return The qualified name (with prefix), or the 505 * empty string if qualified names are not available. 506 */ 507 public String getRawName() 508 { 509 return m_rawName; 510 } 511 512 /** 513 * Get the prefix part of the raw name of the Literal Result Element. 514 * 515 * @return The prefix, or the empty string if noprefix was provided. 516 */ 517 public String getPrefix() 518 { 519 int len=m_rawName.length()-m_localName.length()-1; 520 return (len>0) 521 ? m_rawName.substring(0,len) 522 : ""; 523 } 524 525 526 /** 527 * The "extension-element-prefixes" property, actually contains URIs. 528 * @serial 529 */ 530 private StringVector m_ExtensionElementURIs; 531 532 /** 533 * Set the "extension-element-prefixes" property. 534 * @see <a href="http://www.w3.org/TR/xslt#extension-element">extension-element in XSLT Specification</a> 535 * 536 * @param v Vector of URIs (not prefixes) to set as the "extension-element-prefixes" property 537 */ 538 public void setExtensionElementPrefixes(StringVector v) 539 { 540 m_ExtensionElementURIs = v; 541 } 542 543 /** 544 * @see org.w3c.dom.Node 545 * 546 * @return NamedNodeMap 547 */ 548 public NamedNodeMap getAttributes() 549 { 550 return new LiteralElementAttributes(); 551 } 552 553 public class LiteralElementAttributes implements NamedNodeMap{ 554 private int m_count = -1; 555 556 /** 557 * Construct a NameNodeMap. 558 * 559 */ 560 public LiteralElementAttributes(){ 561 } 562 563 /** 564 * Return the number of Attributes on this Element 565 * 566 * @return The number of nodes in this map. The range of valid child 567 * node indices is <code>0</code> to <code>length-1</code> inclusive 568 */ 569 public int getLength() 570 { 571 if (m_count == -1) 572 { 573 if (null != m_avts) m_count = m_avts.size(); 574 else m_count = 0; 575 } 576 return m_count; 577 } 578 579 /** 580 * Retrieves a node specified by name. 581 * @param name The <code>nodeName</code> of a node to retrieve. 582 * @return A <code>Node</code> (of any type) with the specified 583 * <code>nodeName</code>, or <code>null</code> if it does not 584 * identify any node in this map. 585 */ 586 public Node getNamedItem(String name) 587 { 588 if (getLength() == 0) return null; 589 String uri = null; 590 String localName = name; 591 int index = name.indexOf(":"); 592 if (-1 != index){ 593 uri = name.substring(0, index); 594 localName = name.substring(index+1); 595 } 596 Node retNode = null; 597 Iterator eum = m_avts.iterator(); 598 while (eum.hasNext()){ 599 AVT avt = (AVT) eum.next(); 600 if (localName.equals(avt.getName())) 601 { 602 String nsURI = avt.getURI(); 603 if ((uri == null && nsURI == null) 604 || (uri != null && uri.equals(nsURI))) 605 { 606 retNode = new Attribute(avt, ElemLiteralResult.this); 607 break; 608 } 609 } 610 } 611 return retNode; 612 } 613 614 /** 615 * Retrieves a node specified by local name and namespace URI. 616 * @param namespaceURI Namespace URI of attribute node to get 617 * @param localName Local part of qualified name of attribute node to 618 * get 619 * @return A <code>Node</code> (of any type) with the specified 620 * <code>nodeName</code>, or <code>null</code> if it does not 621 * identify any node in this map. 622 */ 623 public Node getNamedItemNS(String namespaceURI, String localName) 624 { 625 if (getLength() == 0) return null; 626 Node retNode = null; 627 Iterator eum = m_avts.iterator(); 628 while (eum.hasNext()) 629 { 630 AVT avt = (AVT) eum.next(); 631 if (localName.equals(avt.getName())) 632 { 633 String nsURI = avt.getURI(); 634 if ((namespaceURI == null && nsURI == null) 635 || (namespaceURI != null && namespaceURI.equals(nsURI))) 636 { 637 retNode = new Attribute(avt, ElemLiteralResult.this); 638 break; 639 } 640 } 641 } 642 return retNode; 643 } 644 645 /** 646 * Returns the <code>index</code>th item in the map. If <code>index 647 * </code> is greater than or equal to the number of nodes in this 648 * map, this returns <code>null</code>. 649 * @param i The index of the requested item. 650 * @return The node at the <code>index</code>th position in the map, 651 * or <code>null</code> if that is not a valid index. 652 */ 653 public Node item(int i) 654 { 655 if (getLength() == 0 || i >= m_avts.size()) return null; 656 else return 657 new Attribute(((AVT)m_avts.get(i)), 658 ElemLiteralResult.this); 659 } 660 661 /** 662 * @see org.w3c.dom.NamedNodeMap 663 * 664 * @param name of the node to remove 665 * 666 * @return The node removed from this map if a node with such 667 * a name exists. 668 * 669 * @throws DOMException 670 */ 671 public Node removeNamedItem(String name) throws DOMException 672 { 673 throwDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, 674 XSLTErrorResources.NO_MODIFICATION_ALLOWED_ERR); 675 return null; 676 } 677 678 /** 679 * @see org.w3c.dom.NamedNodeMap 680 * 681 * @param namespaceURI Namespace URI of the node to remove 682 * @param localName Local part of qualified name of the node to remove 683 * 684 * @return The node removed from this map if a node with such a local 685 * name and namespace URI exists 686 * 687 * @throws DOMException 688 */ 689 public Node removeNamedItemNS(String namespaceURI, String localName) 690 throws DOMException 691 { 692 throwDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, 693 XSLTErrorResources.NO_MODIFICATION_ALLOWED_ERR); 694 return null; 695 } 696 697 /** 698 * Unimplemented. See org.w3c.dom.NamedNodeMap 699 * 700 * @param A node to store in this map 701 * 702 * @return If the new Node replaces an existing node the replaced 703 * Node is returned, otherwise null is returned 704 * 705 * @throws DOMException 706 */ 707 public Node setNamedItem(Node arg) throws DOMException 708 { 709 throwDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, 710 XSLTErrorResources.NO_MODIFICATION_ALLOWED_ERR); 711 return null; 712 } 713 714 /** 715 * Unimplemented. See org.w3c.dom.NamedNodeMap 716 * 717 * @param A node to store in this map 718 * 719 * @return If the new Node replaces an existing node the replaced 720 * Node is returned, otherwise null is returned 721 * 722 * @throws DOMException 723 */ 724 public Node setNamedItemNS(Node arg) throws DOMException 725 { 726 throwDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, 727 XSLTErrorResources.NO_MODIFICATION_ALLOWED_ERR); 728 return null; 729 } 730 } 731 732 public class Attribute implements Attr{ 733 private AVT m_attribute; 734 private Element m_owner = null; 735 /** 736 * Construct a Attr. 737 * 738 */ 739 public Attribute(AVT avt, Element elem){ 740 m_attribute = avt; 741 m_owner = elem; 742 } 743 744 /** 745 * @see org.w3c.dom.Node 746 * 747 * @param newChild New node to append to the list of this node's 748 * children 749 * 750 * 751 * @throws DOMException 752 */ 753 public Node appendChild(Node newChild) throws DOMException 754 { 755 throwDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, 756 XSLTErrorResources.NO_MODIFICATION_ALLOWED_ERR); 757 return null; 758 } 759 760 /** 761 * @see org.w3c.dom.Node 762 * 763 * @param deep Flag indicating whether to clone deep 764 * (clone member variables) 765 * 766 * @return Returns a duplicate of this node 767 */ 768 public Node cloneNode(boolean deep) 769 { 770 return new Attribute(m_attribute, m_owner); 771 } 772 773 /** 774 * @see org.w3c.dom.Node 775 * 776 * @return null 777 */ 778 public NamedNodeMap getAttributes() 779 { 780 return null; 781 } 782 783 /** 784 * @see org.w3c.dom.Node 785 * 786 * @return a NodeList containing no nodes. 787 */ 788 public NodeList getChildNodes() 789 { 790 return new NodeList(){ 791 public int getLength(){ 792 return 0; 793 } 794 public Node item(int index){ 795 return null; 796 } 797 }; 798 } 799 800 /** 801 * @see org.w3c.dom.Node 802 * 803 * @return null 804 */ 805 public Node getFirstChild() 806 { 807 return null; 808 } 809 810 /** 811 * @see org.w3c.dom.Node 812 * 813 * @return null 814 */ 815 public Node getLastChild() 816 { 817 return null; 818 } 819 820 /** 821 * @see org.w3c.dom.Node 822 * 823 * @return the local part of the qualified name of this node 824 */ 825 public String getLocalName() 826 { 827 return m_attribute.getName(); 828 } 829 830 /** 831 * @see org.w3c.dom.Node 832 * 833 * @return The namespace URI of this node, or null if it is 834 * unspecified 835 */ 836 public String getNamespaceURI() 837 { 838 String uri = m_attribute.getURI(); 839 return (uri.length() == 0)?null:uri; 840 } 841 842 /** 843 * @see org.w3c.dom.Node 844 * 845 * @return null 846 */ 847 public Node getNextSibling() 848 { 849 return null; 850 } 851 852 /** 853 * @see org.w3c.dom.Node 854 * 855 * @return The name of the attribute 856 */ 857 public String getNodeName() 858 { 859 String uri = m_attribute.getURI(); 860 String localName = getLocalName(); 861 return (uri.length() == 0)?localName:uri+":"+localName; 862 } 863 864 /** 865 * @see org.w3c.dom.Node 866 * 867 * @return The node is an Attr 868 */ 869 public short getNodeType() 870 { 871 return ATTRIBUTE_NODE; 872 } 873 874 /** 875 * @see org.w3c.dom.Node 876 * 877 * @return The value of the attribute 878 * 879 * @throws DOMException 880 */ 881 public String getNodeValue() throws DOMException 882 { 883 return m_attribute.getSimpleString(); 884 } 885 886 /** 887 * @see org.w3c.dom.Node 888 * 889 * @return null 890 */ 891 public Document getOwnerDocument() 892 { 893 return m_owner.getOwnerDocument(); 894 } 895 896 /** 897 * @see org.w3c.dom.Node 898 * 899 * @return the containing element node 900 */ 901 public Node getParentNode() 902 { 903 return m_owner; 904 } 905 906 /** 907 * @see org.w3c.dom.Node 908 * 909 * @return The namespace prefix of this node, or null if it is 910 * unspecified 911 */ 912 public String getPrefix() 913 { 914 String uri = m_attribute.getURI(); 915 String rawName = m_attribute.getRawName(); 916 return (uri.length() == 0)? 917 null:rawName.substring(0, rawName.indexOf(":")); 918 } 919 920 /** 921 * @see org.w3c.dom.Node 922 * 923 * @return null 924 */ 925 public Node getPreviousSibling() 926 { 927 return null; 928 } 929 930 /** 931 * @see org.w3c.dom.Node 932 * 933 * @return false 934 */ 935 public boolean hasAttributes() 936 { 937 return false; 938 } 939 940 /** 941 * @see org.w3c.dom.Node 942 * 943 * @return false 944 */ 945 public boolean hasChildNodes() 946 { 947 return false; 948 } 949 950 /** 951 * @see org.w3c.dom.Node 952 * 953 * @param newChild New child node to insert 954 * @param refChild Insert in front of this child 955 * 956 * @return null 957 * 958 * @throws DOMException 959 */ 960 public Node insertBefore(Node newChild, Node refChild) 961 throws DOMException 962 { 963 throwDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, 964 XSLTErrorResources.NO_MODIFICATION_ALLOWED_ERR); 965 return null; 966 } 967 968 /** 969 * @see org.w3c.dom.Node 970 * 971 * @return Returns <code>false</code> 972 * @since DOM Level 2 973 */ 974 public boolean isSupported(String feature, String version) 975 { 976 return false; 977 } 978 979 /** @see org.w3c.dom.Node */ 980 public void normalize(){} 981 982 /** 983 * @see org.w3c.dom.Node 984 * 985 * @param oldChild Child to be removed 986 * 987 * @return null 988 * 989 * @throws DOMException 990 */ 991 public Node removeChild(Node oldChild) throws DOMException 992 { 993 throwDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, 994 XSLTErrorResources.NO_MODIFICATION_ALLOWED_ERR); 995 return null; 996 } 997 998 /** 999 * @see org.w3c.dom.Node 1000 * 1001 * @param newChild Replace existing child with this one 1002 * @param oldChild Existing child to be replaced 1003 * 1004 * @return null 1005 * 1006 * @throws DOMException 1007 */ 1008 public Node replaceChild(Node newChild, Node oldChild) throws DOMException 1009 { 1010 throwDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, 1011 XSLTErrorResources.NO_MODIFICATION_ALLOWED_ERR); 1012 return null; 1013 } 1014 1015 /** 1016 * @see org.w3c.dom.Node 1017 * 1018 * @param nodeValue Value to set this node to 1019 * 1020 * @throws DOMException 1021 */ 1022 public void setNodeValue(String nodeValue) throws DOMException 1023 { 1024 throwDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, 1025 XSLTErrorResources.NO_MODIFICATION_ALLOWED_ERR); 1026 } 1027 1028 /** 1029 * @see org.w3c.dom.Node 1030 * 1031 * @param prefix Prefix to set for this node 1032 * 1033 * @throws DOMException 1034 */ 1035 public void setPrefix(String prefix) throws DOMException 1036 { 1037 throwDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, 1038 XSLTErrorResources.NO_MODIFICATION_ALLOWED_ERR); 1039 } 1040 1041 /** 1042 * 1043 * @return The name of this attribute 1044 */ 1045 public String getName(){ 1046 return m_attribute.getName(); 1047 } 1048 1049 /** 1050 * 1051 * @return The value of this attribute returned as string 1052 */ 1053 public String getValue(){ 1054 return m_attribute.getSimpleString(); 1055 } 1056 1057 /** 1058 * 1059 * @return The Element node this attribute is attached to 1060 * or null if this attribute is not in use 1061 */ 1062 public Element getOwnerElement(){ 1063 return m_owner; 1064 } 1065 1066 /** 1067 * 1068 * @return true 1069 */ 1070 public boolean getSpecified(){ 1071 return true; 1072 } 1073 1074 /** 1075 * @see org.w3c.dom.Attr 1076 * 1077 * @param value Value to set this node to 1078 * 1079 * @throws DOMException 1080 */ 1081 public void setValue(String value) throws DOMException 1082 { 1083 throwDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, 1084 XSLTErrorResources.NO_MODIFICATION_ALLOWED_ERR); 1085 } 1086 1087 public TypeInfo getSchemaTypeInfo() { return null; } 1088 1089 public boolean isId( ) { return false; } 1090 1091 public Object setUserData(String key, 1092 Object data, 1093 UserDataHandler handler) { 1094 return getOwnerDocument().setUserData( key, data, handler); 1095 } 1096 1097 public Object getUserData(String key) { 1098 return getOwnerDocument().getUserData( key); 1099 } 1100 1101 public Object getFeature(String feature, String version) { 1102 return isSupported(feature, version) ? this : null; 1103 } 1104 1105 public boolean isEqualNode(Node arg) { 1106 return arg == this; 1107 } 1108 1109 public String lookupNamespaceURI(String specifiedPrefix) { 1110 return null; 1111 } 1112 1113 public boolean isDefaultNamespace(String namespaceURI) { 1114 return false; 1115 } 1116 1117 public String lookupPrefix(String namespaceURI) { 1118 return null; 1119 } 1120 1121 public boolean isSameNode(Node other) { 1122 // we do not use any wrapper so the answer is obvious 1123 return this == other; 1124 } 1125 1126 public void setTextContent(String textContent) 1127 throws DOMException { 1128 setNodeValue(textContent); 1129 } 1130 1131 public String getTextContent() throws DOMException { 1132 return getNodeValue(); // overriden in some subclasses 1133 } 1134 1135 public short compareDocumentPosition(Node other) throws DOMException { 1136 return 0; 1137 } 1138 1139 public String getBaseURI() { 1140 return null; 1141 } 1142 } 1143 1144 /** 1145 * Get an "extension-element-prefix" property. 1146 * @see <a href="http://www.w3.org/TR/xslt#extension-element">extension-element in XSLT Specification</a> 1147 * 1148 * @param i Index of URI ("extension-element-prefix" property) to get 1149 * 1150 * @return URI at given index ("extension-element-prefix" property) 1151 * 1152 * @throws ArrayIndexOutOfBoundsException 1153 */ 1154 public String getExtensionElementPrefix(int i) 1155 throws ArrayIndexOutOfBoundsException 1156 { 1157 1158 if (null == m_ExtensionElementURIs) 1159 throw new ArrayIndexOutOfBoundsException(); 1160 1161 return m_ExtensionElementURIs.elementAt(i); 1162 } 1163 1164 /** 1165 * Get the number of "extension-element-prefixes" Strings. 1166 * @see <a href="http://www.w3.org/TR/xslt#extension-element">extension-element in XSLT Specification</a> 1167 * 1168 * @return the number of "extension-element-prefixes" Strings 1169 */ 1170 public int getExtensionElementPrefixCount() 1171 { 1172 return (null != m_ExtensionElementURIs) 1173 ? m_ExtensionElementURIs.size() : 0; 1174 } 1175 1176 /** 1177 * Find out if the given "extension-element-prefix" property is defined. 1178 * @see <a href="http://www.w3.org/TR/xslt#extension-element">extension-element in XSLT Specification</a> 1179 * 1180 * @param uri The URI to find 1181 * 1182 * @return True if the given URI is found 1183 */ 1184 public boolean containsExtensionElementURI(String uri) 1185 { 1186 1187 if (null == m_ExtensionElementURIs) 1188 return false; 1189 1190 return m_ExtensionElementURIs.contains(uri); 1191 } 1192 1193 /** 1194 * Get an int constant identifying the type of element. 1195 * @see org.apache.xalan.templates.Constants 1196 * 1197 * @return The token ID for this element 1198 */ 1199 public int getXSLToken() 1200 { 1201 return Constants.ELEMNAME_LITERALRESULT; 1202 } 1203 1204 /** 1205 * Return the node name. 1206 * 1207 * @return The element's name 1208 */ 1209 public String getNodeName() 1210 { 1211 1212 // TODO: Need prefix. 1213 return m_rawName; 1214 } 1215 1216 /** 1217 * The XSLT version as specified by this element. 1218 * @serial 1219 */ 1220 private String m_version; 1221 1222 /** 1223 * Set the "version" property. 1224 * @see <a href="http://www.w3.org/TR/xslt#forwards">forwards in XSLT Specification</a> 1225 * 1226 * @param v Version property value to set 1227 */ 1228 public void setVersion(String v) 1229 { 1230 m_version = v; 1231 } 1232 1233 /** 1234 * Get the "version" property. 1235 * @see <a href="http://www.w3.org/TR/xslt#forwards">forwards in XSLT Specification</a> 1236 * 1237 * @return Version property value 1238 */ 1239 public String getVersion() 1240 { 1241 return m_version; 1242 } 1243 1244 /** 1245 * The "exclude-result-prefixes" property. 1246 * @serial 1247 */ 1248 private StringVector m_excludeResultPrefixes; 1249 1250 /** 1251 * Set the "exclude-result-prefixes" property. 1252 * The designation of a namespace as an excluded namespace is 1253 * effective within the subtree of the stylesheet rooted at 1254 * the element bearing the exclude-result-prefixes or 1255 * xsl:exclude-result-prefixes attribute; a subtree rooted 1256 * at an xsl:stylesheet element does not include any stylesheets 1257 * imported or included by children of that xsl:stylesheet element. 1258 * @see <a href="http://www.w3.org/TR/xslt#literal-result-element">literal-result-element in XSLT Specification</a> 1259 * 1260 * @param v vector of prefixes that are resolvable to strings. 1261 */ 1262 public void setExcludeResultPrefixes(StringVector v) 1263 { 1264 m_excludeResultPrefixes = v; 1265 } 1266 1267 /** 1268 * Tell if the result namespace decl should be excluded. Should be called before 1269 * namespace aliasing (I think). 1270 * 1271 * @param prefix Prefix of namespace to check 1272 * @param uri URI of namespace to check 1273 * 1274 * @return True if the given namespace should be excluded 1275 * 1276 * @throws TransformerException 1277 */ 1278 private boolean excludeResultNSDecl(String prefix, String uri) 1279 throws TransformerException 1280 { 1281 1282 if (null != m_excludeResultPrefixes) 1283 { 1284 return containsExcludeResultPrefix(prefix, uri); 1285 } 1286 1287 return false; 1288 } 1289 1290 /** 1291 * Copy a Literal Result Element into the Result tree, copy the 1292 * non-excluded namespace attributes, copy the attributes not 1293 * of the XSLT namespace, and execute the children of the LRE. 1294 * @see <a href="http://www.w3.org/TR/xslt#literal-result-element">literal-result-element in XSLT Specification</a> 1295 * 1296 * @param transformer non-null reference to the the current transform-time state. 1297 * 1298 * @throws TransformerException 1299 */ 1300 public void execute(TransformerImpl transformer) 1301 throws TransformerException 1302 { 1303 SerializationHandler rhandler = transformer.getSerializationHandler(); 1304 1305 try 1306 { 1307 if (transformer.getDebug()) { 1308 // flush any buffered pending processing before 1309 // the trace event. 1310 rhandler.flushPending(); 1311 transformer.getTraceManager().fireTraceEvent(this); 1312 } 1313 1314 // JJK Bugzilla 3464, test namespace85 -- make sure LRE's 1315 // namespace is asserted even if default, since xsl:element 1316 // may have changed the context. 1317 rhandler.startPrefixMapping(getPrefix(), getNamespace()); 1318 1319 // Add namespace declarations. 1320 executeNSDecls(transformer); 1321 rhandler.startElement(getNamespace(), getLocalName(), getRawName()); 1322 } 1323 catch (SAXException se) 1324 { 1325 throw new TransformerException(se); 1326 } 1327 1328 /* 1329 * If we make it to here we have done a successful startElement() 1330 * we will do an endElement() call for balance, no matter what happens 1331 * in the middle. 1332 */ 1333 1334 // tException remembers if we had an exception "in the middle" 1335 TransformerException tException = null; 1336 try 1337 { 1338 1339 // Process any possible attributes from xsl:use-attribute-sets first 1340 super.execute(transformer); 1341 1342 //xsl:version, excludeResultPrefixes??? 1343 // Process the list of avts next 1344 if (null != m_avts) 1345 { 1346 int nAttrs = m_avts.size(); 1347 1348 for (int i = (nAttrs - 1); i >= 0; i--) 1349 { 1350 AVT avt = (AVT) m_avts.get(i); 1351 XPathContext xctxt = transformer.getXPathContext(); 1352 int sourceNode = xctxt.getCurrentNode(); 1353 String stringedValue = 1354 avt.evaluate(xctxt, sourceNode, this); 1355 1356 if (null != stringedValue) 1357 { 1358 1359 // Important Note: I'm not going to check for excluded namespace 1360 // prefixes here. It seems like it's too expensive, and I'm not 1361 // even sure this is right. But I could be wrong, so this needs 1362 // to be tested against other implementations. 1363 1364 rhandler.addAttribute( 1365 avt.getURI(), 1366 avt.getName(), 1367 avt.getRawName(), 1368 "CDATA", 1369 stringedValue, false); 1370 } 1371 } // end for 1372 } 1373 1374 // Now process all the elements in this subtree 1375 // TODO: Process m_extensionElementPrefixes && m_attributeSetsNames 1376 transformer.executeChildTemplates(this, true); 1377 } 1378 catch (TransformerException te) 1379 { 1380 // thrown in finally to prevent original exception consumed by subsequent exceptions 1381 tException = te; 1382 } 1383 catch (SAXException se) 1384 { 1385 tException = new TransformerException(se); 1386 } 1387 1388 try 1389 { 1390 /* we need to do this endElement() to balance the 1391 * successful startElement() call even if 1392 * there was an exception in the middle. 1393 * Otherwise an exception in the middle could cause a system to hang. 1394 */ 1395 if (transformer.getDebug()) { 1396 // flush any buffered pending processing before 1397 // the trace event. 1398 //rhandler.flushPending(); 1399 transformer.getTraceManager().fireTraceEndEvent(this); 1400 } 1401 rhandler.endElement(getNamespace(), getLocalName(), getRawName()); 1402 } 1403 catch (SAXException se) 1404 { 1405 /* we did call endElement(). If thee was an exception 1406 * in the middle throw that one, otherwise if there 1407 * was an exception from endElement() throw that one. 1408 */ 1409 if (tException != null) 1410 throw tException; 1411 else 1412 throw new TransformerException(se); 1413 } 1414 1415 /* If an exception was thrown in the middle but not with startElement() or 1416 * or endElement() then its time to let it percolate. 1417 */ 1418 if (tException != null) 1419 throw tException; 1420 1421 unexecuteNSDecls(transformer); 1422 1423 // JJK Bugzilla 3464, test namespace85 -- balance explicit start. 1424 try 1425 { 1426 rhandler.endPrefixMapping(getPrefix()); 1427 } 1428 catch (SAXException se) 1429 { 1430 throw new TransformerException(se); 1431 } 1432 } 1433 1434 /** 1435 * Compiling templates requires that we be able to list the AVTs 1436 * ADDED 9/5/2000 to support compilation experiment 1437 * 1438 * @return an Enumeration of the literal result attributes associated 1439 * with this element. 1440 */ 1441 public Iterator enumerateLiteralResultAttributes() 1442 { 1443 return (null == m_avts) ? null : m_avts.iterator(); 1444 } 1445 1446 /** 1447 * Accept a visitor and call the appropriate method 1448 * for this class. 1449 * 1450 * @param visitor The visitor whose appropriate method will be called. 1451 * @return true if the children of the object should be visited. 1452 */ 1453 protected boolean accept(XSLTVisitor visitor) 1454 { 1455 return visitor.visitLiteralResultElement(this); 1456 } 1457 1458 /** 1459 * Call the children visitors. 1460 * @param visitor The visitor whose appropriate method will be called. 1461 */ 1462 protected void callChildVisitors(XSLTVisitor visitor, boolean callAttrs) 1463 { 1464 if (callAttrs && null != m_avts) 1465 { 1466 int nAttrs = m_avts.size(); 1467 1468 for (int i = (nAttrs - 1); i >= 0; i--) 1469 { 1470 AVT avt = (AVT) m_avts.get(i); 1471 avt.callVisitors(visitor); 1472 } 1473 } 1474 super.callChildVisitors(visitor, callAttrs); 1475 } 1476 1477 /** 1478 * Throw a DOMException 1479 * 1480 * @param msg key of the error that occured. 1481 */ 1482 public void throwDOMException(short code, String msg) 1483 { 1484 1485 String themsg = XSLMessages.createMessage(msg, null); 1486 1487 throw new DOMException(code, themsg); 1488 } 1489 1490 }