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    */
setIsLiteralResultAsStylesheet(boolean b)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    */
getIsLiteralResultAsStylesheet()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    */
compose(StylesheetRoot sroot)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    */
addLiteralResultAttribute(AVT avt)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    */
addLiteralResultAttribute(String att)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    */
setXmlSpace(AVT avt)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    */
getLiteralResultAttributeNS(String namespaceURI, String localName)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    */
getAttributeNS(String namespaceURI, String localName)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    */
getLiteralResultAttribute(String name)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    */
getAttribute(String rawName)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    */
containsExcludeResultPrefix(String prefix, String uri)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    */
resolvePrefixTables()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    */
needToCheckExclude()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    */
setNamespace(String ns)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    */
getNamespace()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    */
setLocalName(String localName)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    */
getLocalName()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    */
setRawName(String rawName)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    */
getRawName()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    */
getPrefix()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    */
setExtensionElementPrefixes(StringVector v)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    */
getAttributes()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            */
LiteralElementAttributes()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            */
getLength()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            */
getNamedItem(String name)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            */
getNamedItemNS(String namespaceURI, String localName)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            */
item(int i)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            */
removeNamedItem(String name)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            */
removeNamedItemNS(String namespaceURI, String localName)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            */
setNamedItem(Node arg)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            */
setNamedItemNS(Node arg)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            */
Attribute(AVT avt, Element elem)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            */
appendChild(Node newChild)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            */
cloneNode(boolean deep)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            */
getAttributes()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            */
getChildNodes()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            */
getFirstChild()805           public Node getFirstChild()
806           {
807                   return null;
808           }
809 
810           /**
811            * @see org.w3c.dom.Node
812            *
813            * @return null
814            */
getLastChild()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            */
getLocalName()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            */
getNamespaceURI()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            */
getNextSibling()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            */
getNodeName()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            */
getNodeType()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            */
getNodeValue()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            */
getOwnerDocument()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            */
getParentNode()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            */
getPrefix()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            */
getPreviousSibling()925           public Node getPreviousSibling()
926           {
927                   return null;
928           }
929 
930           /**
931            * @see org.w3c.dom.Node
932            *
933            * @return false
934            */
hasAttributes()935           public boolean hasAttributes()
936           {
937                   return false;
938           }
939 
940           /**
941            * @see org.w3c.dom.Node
942            *
943            * @return false
944            */
hasChildNodes()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            */
insertBefore(Node newChild, Node refChild)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            */
isSupported(String feature, String version)974           public boolean isSupported(String feature, String version)
975           {
976             return false;
977           }
978 
979           /** @see org.w3c.dom.Node */
normalize()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            */
removeChild(Node oldChild)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            */
replaceChild(Node newChild, Node oldChild)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            */
setNodeValue(String nodeValue)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            */
setPrefix(String prefix)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            */
getName()1045           public String getName(){
1046                   return m_attribute.getName();
1047           }
1048 
1049           /**
1050            *
1051            * @return The value of this attribute returned as string
1052            */
getValue()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            */
getOwnerElement()1062           public Element getOwnerElement(){
1063                   return m_owner;
1064           }
1065 
1066           /**
1067            *
1068            * @return true
1069            */
getSpecified()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            */
setValue(String value)1081           public void setValue(String value) throws DOMException
1082           {
1083             throwDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR,
1084                 XSLTErrorResources.NO_MODIFICATION_ALLOWED_ERR);
1085           }
1086 
getSchemaTypeInfo()1087  	  public TypeInfo getSchemaTypeInfo() { return null; }
1088 
isId( )1089   	  public boolean isId( ) { return false; }
1090 
setUserData(String key, Object data, UserDataHandler handler)1091   	  public Object setUserData(String key,
1092                                     Object data,
1093                                     UserDataHandler handler) {
1094         	return getOwnerDocument().setUserData( key, data, handler);
1095   	  }
1096 
getUserData(String key)1097   	  public Object getUserData(String key) {
1098         	return getOwnerDocument().getUserData( key);
1099   	  }
1100 
getFeature(String feature, String version)1101   	  public Object getFeature(String feature, String version) {
1102         	return isSupported(feature, version) ? this : null;
1103    	  }
1104 
isEqualNode(Node arg)1105           public boolean isEqualNode(Node arg) {
1106           	return arg == this;
1107           }
1108 
lookupNamespaceURI(String specifiedPrefix)1109           public String lookupNamespaceURI(String specifiedPrefix) {
1110              	return null;
1111           }
1112 
isDefaultNamespace(String namespaceURI)1113           public boolean isDefaultNamespace(String namespaceURI) {
1114             	return false;
1115           }
1116 
lookupPrefix(String namespaceURI)1117 	  public String lookupPrefix(String namespaceURI) {
1118 	    	return null;
1119 	  }
1120 
isSameNode(Node other)1121   	  public boolean isSameNode(Node other) {
1122         	// we do not use any wrapper so the answer is obvious
1123         	return this == other;
1124   	  }
1125 
setTextContent(String textContent)1126   	  public void setTextContent(String textContent)
1127         	throws DOMException {
1128         	setNodeValue(textContent);
1129   	  }
1130 
getTextContent()1131   	  public String getTextContent() throws DOMException {
1132             	return getNodeValue();  // overriden in some subclasses
1133    	  }
1134 
compareDocumentPosition(Node other)1135     	  public short compareDocumentPosition(Node other) throws DOMException {
1136             	return 0;
1137     	  }
1138 
getBaseURI()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