Home | History | Annotate | Download | only in templates
      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