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 */
21package org.apache.xalan.templates;
22
23import java.util.ArrayList;
24import java.util.Iterator;
25import java.util.List;
26
27import javax.xml.transform.TransformerException;
28
29import org.apache.xalan.res.XSLMessages;
30import org.apache.xalan.res.XSLTErrorResources;
31import org.apache.xalan.transformer.TransformerImpl;
32import org.apache.xml.serializer.SerializationHandler;
33import org.apache.xml.utils.StringVector;
34import org.apache.xpath.XPathContext;
35import org.w3c.dom.Attr;
36import org.w3c.dom.DOMException;
37import org.w3c.dom.Document;
38import org.w3c.dom.Element;
39import org.w3c.dom.NamedNodeMap;
40import org.w3c.dom.Node;
41import org.w3c.dom.NodeList;
42import org.w3c.dom.TypeInfo;
43import org.w3c.dom.UserDataHandler;
44import 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 */
51public 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