1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 /* 19 * $Id: ElemLiteralResult.java 476350 2006-11-17 22:53:23Z minchau $ 20 */ 21 package org.apache.xalan.templates; 22 23 import java.util.ArrayList; 24 import java.util.Iterator; 25 import java.util.List; 26 27 import javax.xml.transform.TransformerException; 28 29 import org.apache.xalan.res.XSLMessages; 30 import org.apache.xalan.res.XSLTErrorResources; 31 import org.apache.xalan.transformer.TransformerImpl; 32 import org.apache.xml.serializer.SerializationHandler; 33 import org.apache.xml.utils.StringVector; 34 import org.apache.xpath.XPathContext; 35 import org.w3c.dom.Attr; 36 import org.w3c.dom.DOMException; 37 import org.w3c.dom.Document; 38 import org.w3c.dom.Element; 39 import org.w3c.dom.NamedNodeMap; 40 import org.w3c.dom.Node; 41 import org.w3c.dom.NodeList; 42 import org.w3c.dom.TypeInfo; 43 import org.w3c.dom.UserDataHandler; 44 import org.xml.sax.SAXException; 45 46 /** 47 * Implement a Literal Result Element. 48 * @see <a href="http://www.w3.org/TR/xslt#literal-result-element">literal-result-element in XSLT Specification</a> 49 * @xsl.usage advanced 50 */ 51 public class ElemLiteralResult extends ElemUse 52 { 53 static final long serialVersionUID = -8703409074421657260L; 54 55 /** The return value as Empty String. */ 56 private static final String EMPTYSTRING = ""; 57 58 /** 59 * Tells if this element represents a root element 60 * that is also the stylesheet element. 61 * TODO: This should be a derived class. 62 * @serial 63 */ 64 private boolean isLiteralResultAsStylesheet = false; 65 66 /** 67 * Set whether this element represents a root element 68 * that is also the stylesheet element. 69 * 70 * 71 * @param b boolean flag indicating whether this element 72 * represents a root element that is also the stylesheet element. 73 */ 74 public void setIsLiteralResultAsStylesheet(boolean b) 75 { 76 isLiteralResultAsStylesheet = b; 77 } 78 79 /** 80 * Return whether this element represents a root element 81 * that is also the stylesheet element. 82 * 83 * 84 * @return boolean flag indicating whether this element 85 * represents a root element that is also the stylesheet element. 86 */ 87 public boolean getIsLiteralResultAsStylesheet() 88 { 89 return isLiteralResultAsStylesheet; 90 } 91 92 /** 93 * This function is called after everything else has been 94 * recomposed, and allows the template to set remaining 95 * values that may be based on some other property that 96 * depends on recomposition. 97 */ 98 public void compose(StylesheetRoot sroot) throws TransformerException 99 { 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.equals("")) && (namespace 255 +":"+avt.getName()).equals(name))|| ((namespace == null || 256 namespace.equals(""))&& 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.equals(""))?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.equals(""))?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.equals(""))? 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 1308 // JJK Bugzilla 3464, test namespace85 -- make sure LRE's 1309 // namespace is asserted even if default, since xsl:element 1310 // may have changed the context. 1311 rhandler.startPrefixMapping(getPrefix(), getNamespace()); 1312 1313 // Add namespace declarations. 1314 executeNSDecls(transformer); 1315 rhandler.startElement(getNamespace(), getLocalName(), getRawName()); 1316 } 1317 catch (SAXException se) 1318 { 1319 throw new TransformerException(se); 1320 } 1321 1322 /* 1323 * If we make it to here we have done a successful startElement() 1324 * we will do an endElement() call for balance, no matter what happens 1325 * in the middle. 1326 */ 1327 1328 // tException remembers if we had an exception "in the middle" 1329 TransformerException tException = null; 1330 try 1331 { 1332 1333 // Process any possible attributes from xsl:use-attribute-sets first 1334 super.execute(transformer); 1335 1336 //xsl:version, excludeResultPrefixes??? 1337 // Process the list of avts next 1338 if (null != m_avts) 1339 { 1340 int nAttrs = m_avts.size(); 1341 1342 for (int i = (nAttrs - 1); i >= 0; i--) 1343 { 1344 AVT avt = (AVT) m_avts.get(i); 1345 XPathContext xctxt = transformer.getXPathContext(); 1346 int sourceNode = xctxt.getCurrentNode(); 1347 String stringedValue = 1348 avt.evaluate(xctxt, sourceNode, this); 1349 1350 if (null != stringedValue) 1351 { 1352 1353 // Important Note: I'm not going to check for excluded namespace 1354 // prefixes here. It seems like it's too expensive, and I'm not 1355 // even sure this is right. But I could be wrong, so this needs 1356 // to be tested against other implementations. 1357 1358 rhandler.addAttribute( 1359 avt.getURI(), 1360 avt.getName(), 1361 avt.getRawName(), 1362 "CDATA", 1363 stringedValue, false); 1364 } 1365 } // end for 1366 } 1367 1368 // Now process all the elements in this subtree 1369 // TODO: Process m_extensionElementPrefixes && m_attributeSetsNames 1370 transformer.executeChildTemplates(this, true); 1371 } 1372 catch (TransformerException te) 1373 { 1374 // thrown in finally to prevent original exception consumed by subsequent exceptions 1375 tException = te; 1376 } 1377 catch (SAXException se) 1378 { 1379 tException = new TransformerException(se); 1380 } 1381 1382 try 1383 { 1384 /* we need to do this endElement() to balance the 1385 * successful startElement() call even if 1386 * there was an exception in the middle. 1387 * Otherwise an exception in the middle could cause a system to hang. 1388 */ 1389 rhandler.endElement(getNamespace(), getLocalName(), getRawName()); 1390 } 1391 catch (SAXException se) 1392 { 1393 /* we did call endElement(). If thee was an exception 1394 * in the middle throw that one, otherwise if there 1395 * was an exception from endElement() throw that one. 1396 */ 1397 if (tException != null) 1398 throw tException; 1399 else 1400 throw new TransformerException(se); 1401 } 1402 1403 /* If an exception was thrown in the middle but not with startElement() or 1404 * or endElement() then its time to let it percolate. 1405 */ 1406 if (tException != null) 1407 throw tException; 1408 1409 unexecuteNSDecls(transformer); 1410 1411 // JJK Bugzilla 3464, test namespace85 -- balance explicit start. 1412 try 1413 { 1414 rhandler.endPrefixMapping(getPrefix()); 1415 } 1416 catch (SAXException se) 1417 { 1418 throw new TransformerException(se); 1419 } 1420 } 1421 1422 /** 1423 * Compiling templates requires that we be able to list the AVTs 1424 * ADDED 9/5/2000 to support compilation experiment 1425 * 1426 * @return an Enumeration of the literal result attributes associated 1427 * with this element. 1428 */ 1429 public Iterator enumerateLiteralResultAttributes() 1430 { 1431 return (null == m_avts) ? null : m_avts.iterator(); 1432 } 1433 1434 /** 1435 * Accept a visitor and call the appropriate method 1436 * for this class. 1437 * 1438 * @param visitor The visitor whose appropriate method will be called. 1439 * @return true if the children of the object should be visited. 1440 */ 1441 protected boolean accept(XSLTVisitor visitor) 1442 { 1443 return visitor.visitLiteralResultElement(this); 1444 } 1445 1446 /** 1447 * Call the children visitors. 1448 * @param visitor The visitor whose appropriate method will be called. 1449 */ 1450 protected void callChildVisitors(XSLTVisitor visitor, boolean callAttrs) 1451 { 1452 if (callAttrs && null != m_avts) 1453 { 1454 int nAttrs = m_avts.size(); 1455 1456 for (int i = (nAttrs - 1); i >= 0; i--) 1457 { 1458 AVT avt = (AVT) m_avts.get(i); 1459 avt.callVisitors(visitor); 1460 } 1461 } 1462 super.callChildVisitors(visitor, callAttrs); 1463 } 1464 1465 /** 1466 * Throw a DOMException 1467 * 1468 * @param msg key of the error that occured. 1469 */ 1470 public void throwDOMException(short code, String msg) 1471 { 1472 1473 String themsg = XSLMessages.createMessage(msg, null); 1474 1475 throw new DOMException(code, themsg); 1476 } 1477 1478 } 1479