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: ElemTemplateElement.java 475981 2006-11-16 23:35:53Z minchau $
20  */
21 package org.apache.xalan.templates;
22 
23 import java.io.Serializable;
24 import java.util.ArrayList;
25 import java.util.Enumeration;
26 import java.util.List;
27 
28 import javax.xml.transform.SourceLocator;
29 import javax.xml.transform.TransformerException;
30 
31 import org.apache.xalan.res.XSLMessages;
32 import org.apache.xalan.res.XSLTErrorResources;
33 import org.apache.xalan.transformer.TransformerImpl;
34 import org.apache.xml.serializer.SerializationHandler;
35 import org.apache.xml.utils.PrefixResolver;
36 import org.apache.xml.utils.UnImplNode;
37 import org.apache.xpath.ExpressionNode;
38 import org.apache.xpath.WhitespaceStrippingElementMatcher;
39 
40 import org.w3c.dom.DOMException;
41 import org.w3c.dom.Document;
42 import org.w3c.dom.Node;
43 import org.w3c.dom.NodeList;
44 
45 import org.xml.sax.helpers.NamespaceSupport;
46 
47 /**
48  * An instance of this class represents an element inside
49  * an xsl:template class.  It has a single "execute" method
50  * which is expected to perform the given action on the
51  * result tree.
52  * This class acts like a Element node, and implements the
53  * Element interface, but is not a full implementation
54  * of that interface... it only implements enough for
55  * basic traversal of the tree.
56  *
57  * @see Stylesheet
58  * @xsl.usage advanced
59  */
60 public class ElemTemplateElement extends UnImplNode
61         implements PrefixResolver, Serializable, ExpressionNode,
62                    WhitespaceStrippingElementMatcher, XSLTVisitable
63 {
64     static final long serialVersionUID = 4440018597841834447L;
65 
66   /**
67    * Construct a template element instance.
68    *
69    */
ElemTemplateElement()70   public ElemTemplateElement(){}
71 
72   /**
73    * Tell if this template is a compiled template.
74    *
75    * @return Boolean flag indicating whether this is a compiled template
76    */
isCompiledTemplate()77   public boolean isCompiledTemplate()
78   {
79     return false;
80   }
81 
82   /**
83    * Get an integer representation of the element type.
84    *
85    * @return An integer representation of the element, defined in the
86    *     Constants class.
87    * @see org.apache.xalan.templates.Constants
88    */
getXSLToken()89   public int getXSLToken()
90   {
91     return Constants.ELEMNAME_UNDEFINED;
92   }
93 
94   /**
95    * Return the node name.
96    *
97    * @return An invalid node name
98    */
getNodeName()99   public String getNodeName()
100   {
101     return "Unknown XSLT Element";
102   }
103 
104   /**
105    * For now, just return the result of getNodeName(), which
106    * the local name.
107    *
108    * @return The result of getNodeName().
109    */
getLocalName()110   public String getLocalName()
111   {
112 
113     return getNodeName();
114   }
115 
116 
117   /**
118    * This function will be called on top-level elements
119    * only, just before the transform begins.
120    *
121    * @param transformer The XSLT TransformerFactory.
122    *
123    * @throws TransformerException
124    */
runtimeInit(TransformerImpl transformer)125   public void runtimeInit(TransformerImpl transformer) throws TransformerException{}
126 
127   /**
128    * Execute the element's primary function.  Subclasses of this
129    * function may recursivly execute down the element tree.
130    *
131    * @param transformer The XSLT TransformerFactory.
132    *
133    * @throws TransformerException if any checked exception occurs.
134    */
execute( TransformerImpl transformer)135   public void execute(
136           TransformerImpl transformer)
137             throws TransformerException{}
138 
139   /**
140    * Get the owning "composed" stylesheet.  This looks up the
141    * inheritance chain until it calls getStylesheetComposed
142    * on a Stylesheet object, which will Get the owning
143    * aggregated stylesheet, or that stylesheet if it is aggregated.
144    *
145    * @return the owning "composed" stylesheet.
146    */
getStylesheetComposed()147   public StylesheetComposed getStylesheetComposed()
148   {
149     return m_parentNode.getStylesheetComposed();
150   }
151 
152   /**
153    * Get the owning stylesheet.  This looks up the
154    * inheritance chain until it calls getStylesheet
155    * on a Stylesheet object, which will return itself.
156    *
157    * @return the owning stylesheet
158    */
getStylesheet()159   public Stylesheet getStylesheet()
160   {
161     return (null==m_parentNode) ? null : m_parentNode.getStylesheet();
162   }
163 
164   /**
165    * Get the owning root stylesheet.  This looks up the
166    * inheritance chain until it calls StylesheetRoot
167    * on a Stylesheet object, which will return a reference
168    * to the root stylesheet.
169    *
170    * @return the owning root stylesheet
171    */
getStylesheetRoot()172   public StylesheetRoot getStylesheetRoot()
173   {
174     return m_parentNode.getStylesheetRoot();
175   }
176 
177   /**
178    * This function is called during recomposition to
179    * control how this element is composed.
180    */
recompose(StylesheetRoot root)181   public void recompose(StylesheetRoot root) throws TransformerException
182   {
183   }
184 
185   /**
186    * This function is called after everything else has been
187    * recomposed, and allows the template to set remaining
188    * values that may be based on some other property that
189    * depends on recomposition.
190    */
compose(StylesheetRoot sroot)191   public void compose(StylesheetRoot sroot) throws TransformerException
192   {
193     resolvePrefixTables();
194     ElemTemplateElement t = getFirstChildElem();
195     m_hasTextLitOnly = ((t != null)
196               && (t.getXSLToken() == Constants.ELEMNAME_TEXTLITERALRESULT)
197               && (t.getNextSiblingElem() == null));
198 
199     StylesheetRoot.ComposeState cstate = sroot.getComposeState();
200     cstate.pushStackMark();
201   }
202 
203   /**
204    * This after the template's children have been composed.
205    */
endCompose(StylesheetRoot sroot)206   public void endCompose(StylesheetRoot sroot) throws TransformerException
207   {
208     StylesheetRoot.ComposeState cstate = sroot.getComposeState();
209     cstate.popStackMark();
210   }
211 
212   /**
213    * Throw a template element runtime error.  (Note: should we throw a TransformerException instead?)
214    *
215    * @param msg key of the error that occured.
216    * @param args Arguments to be used in the message
217    */
error(String msg, Object[] args)218   public void error(String msg, Object[] args)
219   {
220 
221     String themsg = XSLMessages.createMessage(msg, args);
222 
223     throw new RuntimeException(XSLMessages.createMessage(
224                                     XSLTErrorResources.ER_ELEMTEMPLATEELEM_ERR,
225                                     new Object[]{ themsg }));
226   }
227 
228   /*
229    * Throw an error.
230    *
231    * @param msg Message key for the error
232    *
233    */
error(String msg)234   public void error(String msg)
235   {
236     error(msg, null);
237   }
238 
239 
240   // Implemented DOM Element methods.
241   /**
242    * Add a child to the child list.
243    * NOTE: This presumes the child did not previously have a parent.
244    * Making that assumption makes this a less expensive operation -- but
245    * requires that if you *do* want to reparent a node, you use removeChild()
246    * first to remove it from its previous context. Failing to do so will
247    * damage the tree.
248    *
249    * @param newChild Child to be added to child list
250    *
251    * @return Child just added to the child list
252    * @throws DOMException
253    */
appendChild(Node newChild)254   public Node appendChild(Node newChild) throws DOMException
255   {
256 
257     if (null == newChild)
258     {
259       error(XSLTErrorResources.ER_NULL_CHILD, null);  //"Trying to add a null child!");
260     }
261 
262     ElemTemplateElement elem = (ElemTemplateElement) newChild;
263 
264     if (null == m_firstChild)
265     {
266       m_firstChild = elem;
267     }
268     else
269     {
270       ElemTemplateElement last = (ElemTemplateElement) getLastChild();
271 
272       last.m_nextSibling = elem;
273     }
274 
275     elem.m_parentNode = this;
276 
277     return newChild;
278   }
279 
280   /**
281    * Add a child to the child list.
282    * NOTE: This presumes the child did not previously have a parent.
283    * Making that assumption makes this a less expensive operation -- but
284    * requires that if you *do* want to reparent a node, you use removeChild()
285    * first to remove it from its previous context. Failing to do so will
286    * damage the tree.
287    *
288    * @param elem Child to be added to child list
289    *
290    * @return Child just added to the child list
291    */
appendChild(ElemTemplateElement elem)292   public ElemTemplateElement appendChild(ElemTemplateElement elem)
293   {
294 
295     if (null == elem)
296     {
297       error(XSLTErrorResources.ER_NULL_CHILD, null);  //"Trying to add a null child!");
298     }
299 
300     if (null == m_firstChild)
301     {
302       m_firstChild = elem;
303     }
304     else
305     {
306       ElemTemplateElement last = getLastChildElem();
307 
308       last.m_nextSibling = elem;
309     }
310 
311     elem.setParentElem(this);
312 
313     return elem;
314   }
315 
316 
317   /**
318    * Tell if there are child nodes.
319    *
320    * @return True if there are child nodes
321    */
hasChildNodes()322   public boolean hasChildNodes()
323   {
324     return (null != m_firstChild);
325   }
326 
327   /**
328    * Get the type of the node.
329    *
330    * @return Constant for this node type
331    */
getNodeType()332   public short getNodeType()
333   {
334     return org.w3c.dom.Node.ELEMENT_NODE;
335   }
336 
337   /**
338    * Return the nodelist (same reference).
339    *
340    * @return The nodelist containing the child nodes (this)
341    */
getChildNodes()342   public NodeList getChildNodes()
343   {
344     return this;
345   }
346 
347   /**
348    * Remove a child.
349    * ADDED 9/8/200 to support compilation.
350    * TODO: ***** Alternative is "removeMe() from my parent if any"
351    * ... which is less well checked, but more convenient in some cases.
352    * Given that we assume only experts are calling this class, it might
353    * be preferable. It's less DOMish, though.
354    *
355    * @param childETE The child to remove. This operation is a no-op
356    * if oldChild is not a child of this node.
357    *
358    * @return the removed child, or null if the specified
359    * node was not a child of this element.
360    */
removeChild(ElemTemplateElement childETE)361   public ElemTemplateElement removeChild(ElemTemplateElement childETE)
362   {
363 
364     if (childETE == null || childETE.m_parentNode != this)
365       return null;
366 
367     // Pointers to the child
368     if (childETE == m_firstChild)
369       m_firstChild = childETE.m_nextSibling;
370     else
371     {
372       ElemTemplateElement prev = childETE.getPreviousSiblingElem();
373 
374       prev.m_nextSibling = childETE.m_nextSibling;
375     }
376 
377     // Pointers from the child
378     childETE.m_parentNode = null;
379     childETE.m_nextSibling = null;
380 
381     return childETE;
382   }
383 
384   /**
385    * Replace the old child with a new child.
386    *
387    * @param newChild New child to replace with
388    * @param oldChild Old child to be replaced
389    *
390    * @return The new child
391    *
392    * @throws DOMException
393    */
replaceChild(Node newChild, Node oldChild)394   public Node replaceChild(Node newChild, Node oldChild) throws DOMException
395   {
396 
397     if (oldChild == null || oldChild.getParentNode() != this)
398       return null;
399 
400     ElemTemplateElement newChildElem = ((ElemTemplateElement) newChild);
401     ElemTemplateElement oldChildElem = ((ElemTemplateElement) oldChild);
402 
403     // Fix up previous sibling.
404     ElemTemplateElement prev =
405       (ElemTemplateElement) oldChildElem.getPreviousSibling();
406 
407     if (null != prev)
408       prev.m_nextSibling = newChildElem;
409 
410     // Fix up parent (this)
411     if (m_firstChild == oldChildElem)
412       m_firstChild = newChildElem;
413 
414     newChildElem.m_parentNode = this;
415     oldChildElem.m_parentNode = null;
416     newChildElem.m_nextSibling = oldChildElem.m_nextSibling;
417     oldChildElem.m_nextSibling = null;
418 
419     // newChildElem.m_stylesheet = oldChildElem.m_stylesheet;
420     // oldChildElem.m_stylesheet = null;
421     return newChildElem;
422   }
423 
424   /**
425    * Unimplemented. See org.w3c.dom.Node
426    *
427    * @param newChild New child node to insert
428    * @param refChild Insert in front of this child
429    *
430    * @return null
431    *
432    * @throws DOMException
433    */
insertBefore(Node newChild, Node refChild)434   public Node insertBefore(Node newChild, Node refChild) throws DOMException
435   {
436   	if(null == refChild)
437   	{
438   		appendChild(newChild);
439   		return newChild;
440   	}
441 
442   	if(newChild == refChild)
443   	{
444   		// hmm...
445   		return newChild;
446   	}
447 
448     Node node = m_firstChild;
449     Node prev = null;
450     boolean foundit = false;
451 
452     while (null != node)
453     {
454     	// If the newChild is already in the tree, it is first removed.
455     	if(newChild == node)
456     	{
457     		if(null != prev)
458     			((ElemTemplateElement)prev).m_nextSibling =
459     				(ElemTemplateElement)node.getNextSibling();
460     		else
461     			m_firstChild = (ElemTemplateElement)node.getNextSibling();
462     		node = node.getNextSibling();
463     		continue; // prev remains the same.
464     	}
465     	if(refChild == node)
466     	{
467     		if(null != prev)
468     		{
469     			((ElemTemplateElement)prev).m_nextSibling = (ElemTemplateElement)newChild;
470     		}
471     		else
472     		{
473     			m_firstChild = (ElemTemplateElement)newChild;
474     		}
475     		((ElemTemplateElement)newChild).m_nextSibling = (ElemTemplateElement)refChild;
476     		((ElemTemplateElement)newChild).setParentElem(this);
477     		prev = newChild;
478     		node = node.getNextSibling();
479     		foundit = true;
480     		continue;
481     	}
482     	prev = node;
483     	node = node.getNextSibling();
484     }
485 
486     if(!foundit)
487     	throw new DOMException(DOMException.NOT_FOUND_ERR,
488     		"refChild was not found in insertBefore method!");
489     else
490     	return newChild;
491   }
492 
493 
494   /**
495    * Replace the old child with a new child.
496    *
497    * @param newChildElem New child to replace with
498    * @param oldChildElem Old child to be replaced
499    *
500    * @return The new child
501    *
502    * @throws DOMException
503    */
replaceChild(ElemTemplateElement newChildElem, ElemTemplateElement oldChildElem)504   public ElemTemplateElement replaceChild(ElemTemplateElement newChildElem,
505                                           ElemTemplateElement oldChildElem)
506   {
507 
508     if (oldChildElem == null || oldChildElem.getParentElem() != this)
509       return null;
510 
511     // Fix up previous sibling.
512     ElemTemplateElement prev =
513       oldChildElem.getPreviousSiblingElem();
514 
515     if (null != prev)
516       prev.m_nextSibling = newChildElem;
517 
518     // Fix up parent (this)
519     if (m_firstChild == oldChildElem)
520       m_firstChild = newChildElem;
521 
522     newChildElem.m_parentNode = this;
523     oldChildElem.m_parentNode = null;
524     newChildElem.m_nextSibling = oldChildElem.m_nextSibling;
525     oldChildElem.m_nextSibling = null;
526 
527     // newChildElem.m_stylesheet = oldChildElem.m_stylesheet;
528     // oldChildElem.m_stylesheet = null;
529     return newChildElem;
530   }
531 
532   /**
533    * NodeList method: Count the immediate children of this node
534    *
535    * @return The count of children of this node
536    */
getLength()537   public int getLength()
538   {
539 
540     // It is assumed that the getChildNodes call synchronized
541     // the children. Therefore, we can access the first child
542     // reference directly.
543     int count = 0;
544 
545     for (ElemTemplateElement node = m_firstChild; node != null;
546             node = node.m_nextSibling)
547     {
548       count++;
549     }
550 
551     return count;
552   }  // getLength():int
553 
554   /**
555    * NodeList method: Return the Nth immediate child of this node, or
556    * null if the index is out of bounds.
557    *
558    * @param index Index of child to find
559    * @return org.w3c.dom.Node: the child node at given index
560    */
item(int index)561   public Node item(int index)
562   {
563 
564     // It is assumed that the getChildNodes call synchronized
565     // the children. Therefore, we can access the first child
566     // reference directly.
567     ElemTemplateElement node = m_firstChild;
568 
569     for (int i = 0; i < index && node != null; i++)
570     {
571       node = node.m_nextSibling;
572     }
573 
574     return node;
575   }  // item(int):Node
576 
577   /**
578    * Get the stylesheet owner.
579    *
580    * @return The stylesheet owner
581    */
getOwnerDocument()582   public Document getOwnerDocument()
583   {
584     return getStylesheet();
585   }
586 
587   /**
588    * Get the owning xsl:template element.
589    *
590    * @return The owning xsl:template element, this element if it is a xsl:template, or null if not found.
591    */
getOwnerXSLTemplate()592   public ElemTemplate getOwnerXSLTemplate()
593   {
594   	ElemTemplateElement el = this;
595   	int type = el.getXSLToken();
596   	while((null != el) && (type != Constants.ELEMNAME_TEMPLATE))
597   	{
598     	el = el.getParentElem();
599     	if(null != el)
600   			type = el.getXSLToken();
601   	}
602   	return (ElemTemplate)el;
603   }
604 
605 
606   /**
607    * Return the element name.
608    *
609    * @return The element name
610    */
getTagName()611   public String getTagName()
612   {
613     return getNodeName();
614   }
615 
616   /**
617    * Tell if this element only has one text child, for optimization purposes.
618    * @return true of this element only has one text literal child.
619    */
hasTextLitOnly()620   public boolean hasTextLitOnly()
621   {
622     return m_hasTextLitOnly;
623   }
624 
625   /**
626    * Return the base identifier.
627    *
628    * @return The base identifier
629    */
getBaseIdentifier()630   public String getBaseIdentifier()
631   {
632 
633     // Should this always be absolute?
634     return this.getSystemId();
635   }
636 
637   /** line number where the current document event ends.
638    *  @serial         */
639   private int m_lineNumber;
640 
641   /** line number where the current document event ends.
642    *  @serial         */
643   private int m_endLineNumber;
644 
645   /**
646    * Return the line number where the current document event ends.
647    * Note that this is the line position of the first character
648    * after the text associated with the document event.
649    * @return The line number, or -1 if none is available.
650    * @see #getColumnNumber
651    */
getEndLineNumber()652   public int getEndLineNumber()
653   {
654 	return m_endLineNumber;
655   }
656 
657   /**
658    * Return the line number where the current document event ends.
659    * Note that this is the line position of the first character
660    * after the text associated with the document event.
661    * @return The line number, or -1 if none is available.
662    * @see #getColumnNumber
663    */
getLineNumber()664   public int getLineNumber()
665   {
666     return m_lineNumber;
667   }
668 
669   /** the column number where the current document event ends.
670    *  @serial        */
671   private int m_columnNumber;
672 
673   /** the column number where the current document event ends.
674    *  @serial        */
675   private int m_endColumnNumber;
676 
677   /**
678    * Return the column number where the current document event ends.
679    * Note that this is the column number of the first
680    * character after the text associated with the document
681    * event.  The first column in a line is position 1.
682    * @return The column number, or -1 if none is available.
683    * @see #getLineNumber
684    */
getEndColumnNumber()685   public int getEndColumnNumber()
686   {
687 	return m_endColumnNumber;
688   }
689 
690   /**
691    * Return the column number where the current document event ends.
692    * Note that this is the column number of the first
693    * character after the text associated with the document
694    * event.  The first column in a line is position 1.
695    * @return The column number, or -1 if none is available.
696    * @see #getLineNumber
697    */
getColumnNumber()698   public int getColumnNumber()
699   {
700     return m_columnNumber;
701   }
702 
703   /**
704    * Return the public identifier for the current document event.
705    * <p>This will be the public identifier
706    * @return A string containing the public identifier, or
707    *         null if none is available.
708    * @see #getSystemId
709    */
getPublicId()710   public String getPublicId()
711   {
712     return (null != m_parentNode) ? m_parentNode.getPublicId() : null;
713   }
714 
715   /**
716    * Return the system identifier for the current document event.
717    *
718    * <p>If the system identifier is a URL, the parser must resolve it
719    * fully before passing it to the application.</p>
720    *
721    * @return A string containing the system identifier, or null
722    *         if none is available.
723    * @see #getPublicId
724    */
getSystemId()725   public String getSystemId()
726   {
727     Stylesheet sheet=getStylesheet();
728     return (sheet==null) ? null : sheet.getHref();
729   }
730 
731   /**
732    * Set the location information for this element.
733    *
734    * @param locator Source Locator with location information for this element
735    */
setLocaterInfo(SourceLocator locator)736   public void setLocaterInfo(SourceLocator locator)
737   {
738     m_lineNumber = locator.getLineNumber();
739     m_columnNumber = locator.getColumnNumber();
740   }
741 
742   /**
743    * Set the end location information for this element.
744    *
745    * @param locator Source Locator with location information for this element
746    */
setEndLocaterInfo(SourceLocator locator)747   public void setEndLocaterInfo(SourceLocator locator)
748   {
749 	m_endLineNumber = locator.getLineNumber();
750 	m_endColumnNumber = locator.getColumnNumber();
751   }
752 
753   /**
754    * Tell if this element has the default space handling
755    * turned off or on according to the xml:space attribute.
756    * @serial
757    */
758   private boolean m_defaultSpace = true;
759 
760   /**
761    * Tell if this element only has one text child, for optimization purposes.
762    * @serial
763    */
764   private boolean m_hasTextLitOnly = false;
765 
766   /**
767    * Tell if this element only has one text child, for optimization purposes.
768    * @serial
769    */
770   protected boolean m_hasVariableDecl = false;
771 
hasVariableDecl()772   public boolean hasVariableDecl()
773   {
774     return m_hasVariableDecl;
775   }
776 
777   /**
778    * Set the "xml:space" attribute.
779    * A text node is preserved if an ancestor element of the text node
780    * has an xml:space attribute with a value of preserve, and
781    * no closer ancestor element has xml:space with a value of default.
782    * @see <a href="http://www.w3.org/TR/xslt#strip">strip in XSLT Specification</a>
783    * @see <a href="http://www.w3.org/TR/xslt#section-Creating-Text">section-Creating-Text in XSLT Specification</a>
784    *
785    * @param v  Enumerated value, either Constants.ATTRVAL_PRESERVE
786    * or Constants.ATTRVAL_STRIP.
787    */
setXmlSpace(int v)788   public void setXmlSpace(int v)
789   {
790     m_defaultSpace = ((Constants.ATTRVAL_STRIP == v) ? true : false);
791   }
792 
793   /**
794    * Get the "xml:space" attribute.
795    * A text node is preserved if an ancestor element of the text node
796    * has an xml:space attribute with a value of preserve, and
797    * no closer ancestor element has xml:space with a value of default.
798    * @see <a href="http://www.w3.org/TR/xslt#strip">strip in XSLT Specification</a>
799    * @see <a href="http://www.w3.org/TR/xslt#section-Creating-Text">section-Creating-Text in XSLT Specification</a>
800    *
801    * @return The value of the xml:space attribute
802    */
getXmlSpace()803   public boolean getXmlSpace()
804   {
805     return m_defaultSpace;
806   }
807 
808   /**
809    * The list of namespace declarations for this element only.
810    * @serial
811    */
812   private List m_declaredPrefixes;
813 
814   /**
815    * Return a table that contains all prefixes available
816    * within this element context.
817    *
818    * @return Vector containing the prefixes available within this
819    * element context
820    */
getDeclaredPrefixes()821   public List getDeclaredPrefixes()
822   {
823     return m_declaredPrefixes;
824   }
825 
826   /**
827    * From the SAX2 helper class, set the namespace table for
828    * this element.  Take care to call resolveInheritedNamespaceDecls.
829    * after all namespace declarations have been added.
830    *
831    * @param nsSupport non-null reference to NamespaceSupport from
832    * the ContentHandler.
833    *
834    * @throws TransformerException
835    */
setPrefixes(NamespaceSupport nsSupport)836   public void setPrefixes(NamespaceSupport nsSupport) throws TransformerException
837   {
838     setPrefixes(nsSupport, false);
839   }
840 
841   /**
842    * Copy the namespace declarations from the NamespaceSupport object.
843    * Take care to call resolveInheritedNamespaceDecls.
844    * after all namespace declarations have been added.
845    *
846    * @param nsSupport non-null reference to NamespaceSupport from
847    * the ContentHandler.
848    * @param excludeXSLDecl true if XSLT namespaces should be ignored.
849    *
850    * @throws TransformerException
851    */
setPrefixes(NamespaceSupport nsSupport, boolean excludeXSLDecl)852   public void setPrefixes(NamespaceSupport nsSupport, boolean excludeXSLDecl)
853           throws TransformerException
854   {
855 
856     Enumeration decls = nsSupport.getDeclaredPrefixes();
857 
858     while (decls.hasMoreElements())
859     {
860       String prefix = (String) decls.nextElement();
861 
862       if (null == m_declaredPrefixes)
863         m_declaredPrefixes = new ArrayList();
864 
865       String uri = nsSupport.getURI(prefix);
866 
867       if (excludeXSLDecl && uri.equals(Constants.S_XSLNAMESPACEURL))
868         continue;
869 
870       // System.out.println("setPrefixes - "+prefix+", "+uri);
871       XMLNSDecl decl = new XMLNSDecl(prefix, uri, false);
872 
873       m_declaredPrefixes.add(decl);
874     }
875   }
876 
877   /**
878    * Fullfill the PrefixResolver interface.  Calling this for this class
879    * will throw an error.
880    *
881    * @param prefix The prefix to look up, which may be an empty string ("")
882    *               for the default Namespace.
883    * @param context The node context from which to look up the URI.
884    *
885    * @return null if the error listener does not choose to throw an exception.
886    */
getNamespaceForPrefix(String prefix, org.w3c.dom.Node context)887   public String getNamespaceForPrefix(String prefix, org.w3c.dom.Node context)
888   {
889     this.error(XSLTErrorResources.ER_CANT_RESOLVE_NSPREFIX, null);
890 
891     return null;
892   }
893 
894   /**
895    * Given a namespace, get the corrisponding prefix.
896    * 9/15/00: This had been iteratively examining the m_declaredPrefixes
897    * field for this node and its parents. That makes life difficult for
898    * the compilation experiment, which doesn't have a static vector of
899    * local declarations. Replaced a recursive solution, which permits
900    * easier subclassing/overriding.
901    *
902    * @param prefix non-null reference to prefix string, which should map
903    *               to a namespace URL.
904    *
905    * @return The namespace URL that the prefix maps to, or null if no
906    *         mapping can be found.
907    */
getNamespaceForPrefix(String prefix)908   public String getNamespaceForPrefix(String prefix)
909   {
910 //    if (null != prefix && prefix.equals("xmlns"))
911 //    {
912 //      return Constants.S_XMLNAMESPACEURI;
913 //    }
914 
915     List nsDecls = m_declaredPrefixes;
916 
917     if (null != nsDecls)
918     {
919       int n = nsDecls.size();
920       if(prefix.equals(Constants.ATTRVAL_DEFAULT_PREFIX))
921       {
922         prefix = "";
923       }
924 
925       for (int i = 0; i < n; i++)
926       {
927         XMLNSDecl decl = (XMLNSDecl) nsDecls.get(i);
928 
929         if (prefix.equals(decl.getPrefix()))
930           return decl.getURI();
931       }
932     }
933 
934     // Not found; ask our ancestors
935     if (null != m_parentNode)
936       return m_parentNode.getNamespaceForPrefix(prefix);
937 
938     // JJK: No ancestors; try implicit
939     // %REVIEW% Are there literals somewhere that we should use instead?
940     // %REVIEW% Is this really the best place to patch?
941     if("xml".equals(prefix))
942       return "http://www.w3.org/XML/1998/namespace";
943 
944     // No parent, so no definition
945     return null;
946   }
947 
948   /**
949    * The table of {@link XMLNSDecl}s for this element
950    * and all parent elements, screened for excluded prefixes.
951    * @serial
952    */
953   private List m_prefixTable;
954 
955   /**
956    * Return a table that contains all prefixes available
957    * within this element context.
958    *
959    * @return reference to vector of {@link XMLNSDecl}s, which may be null.
960    */
getPrefixTable()961   List getPrefixTable()
962   {
963     return m_prefixTable;
964   }
965 
setPrefixTable(List list)966   void setPrefixTable(List list) {
967       m_prefixTable = list;
968   }
969 
970   /**
971    * Get whether or not the passed URL is contained flagged by
972    * the "extension-element-prefixes" property.  This method is overridden
973    * by {@link ElemLiteralResult#containsExcludeResultPrefix}.
974    * @see <a href="http://www.w3.org/TR/xslt#extension-element">extension-element in XSLT Specification</a>
975    *
976    * @param prefix non-null reference to prefix that might be excluded.
977    *
978    * @return true if the prefix should normally be excluded.
979    */
containsExcludeResultPrefix(String prefix, String uri)980   public boolean containsExcludeResultPrefix(String prefix, String uri)
981   {
982     ElemTemplateElement parent = this.getParentElem();
983     if(null != parent)
984       return parent.containsExcludeResultPrefix(prefix, uri);
985 
986     return false;
987   }
988 
989   /**
990    * Tell if the result namespace decl should be excluded.  Should be called before
991    * namespace aliasing (I think).
992    *
993    * @param prefix non-null reference to prefix.
994    * @param uri reference to namespace that prefix maps to, which is protected
995    *            for null, but should really never be passed as null.
996    *
997    * @return true if the given namespace should be excluded.
998    *
999    * @throws TransformerException
1000    */
excludeResultNSDecl(String prefix, String uri)1001   private boolean excludeResultNSDecl(String prefix, String uri)
1002           throws TransformerException
1003   {
1004 
1005     if (uri != null)
1006     {
1007       if (uri.equals(Constants.S_XSLNAMESPACEURL)
1008               || getStylesheet().containsExtensionElementURI(uri))
1009         return true;
1010 
1011       if (containsExcludeResultPrefix(prefix, uri))
1012         return true;
1013     }
1014 
1015     return false;
1016   }
1017 
1018   /**
1019    * Combine the parent's namespaces with this namespace
1020    * for fast processing, taking care to reference the
1021    * parent's namespace if this namespace adds nothing new.
1022    * (Recursive method, walking the elements depth-first,
1023    * processing parents before children).
1024    * Note that this method builds m_prefixTable with aliased
1025    * namespaces, *not* the original namespaces.
1026    *
1027    * @throws TransformerException
1028    */
resolvePrefixTables()1029   public void resolvePrefixTables() throws TransformerException
1030   {
1031     // Always start with a fresh prefix table!
1032     setPrefixTable(null);
1033 
1034     // If we have declared declarations, then we look for
1035     // a parent that has namespace decls, and add them
1036     // to this element's decls.  Otherwise we just point
1037     // to the parent that has decls.
1038     if (null != this.m_declaredPrefixes)
1039     {
1040       StylesheetRoot stylesheet = this.getStylesheetRoot();
1041 
1042       // Add this element's declared prefixes to the
1043       // prefix table.
1044       int n = m_declaredPrefixes.size();
1045 
1046       for (int i = 0; i < n; i++)
1047       {
1048         XMLNSDecl decl = (XMLNSDecl) m_declaredPrefixes.get(i);
1049         String prefix = decl.getPrefix();
1050         String uri = decl.getURI();
1051         if(null == uri)
1052           uri = "";
1053         boolean shouldExclude = excludeResultNSDecl(prefix, uri);
1054 
1055         // Create a new prefix table if one has not already been created.
1056         if (null == m_prefixTable)
1057             setPrefixTable(new ArrayList());
1058 
1059         NamespaceAlias nsAlias = stylesheet.getNamespaceAliasComposed(uri);
1060         if(null != nsAlias)
1061         {
1062           // Should I leave the non-aliased element in the table as
1063           // an excluded element?
1064 
1065           // The exclusion should apply to the non-aliased prefix, so
1066           // we don't calculate it here.  -sb
1067           // Use stylesheet prefix, as per xsl WG
1068           decl = new XMLNSDecl(nsAlias.getStylesheetPrefix(),
1069                               nsAlias.getResultNamespace(), shouldExclude);
1070         }
1071         else
1072           decl = new XMLNSDecl(prefix, uri, shouldExclude);
1073 
1074         m_prefixTable.add(decl);
1075 
1076       }
1077     }
1078 
1079     ElemTemplateElement parent = this.getParentNodeElem();
1080 
1081     if (null != parent)
1082     {
1083 
1084       // The prefix table of the parent should never be null!
1085       List prefixes = parent.m_prefixTable;
1086 
1087       if (null == m_prefixTable && !needToCheckExclude())
1088       {
1089 
1090         // Nothing to combine, so just use parent's table!
1091         setPrefixTable(parent.m_prefixTable);
1092       }
1093       else
1094       {
1095 
1096         // Add the prefixes from the parent's prefix table.
1097         int n = prefixes.size();
1098 
1099         for (int i = 0; i < n; i++)
1100         {
1101           XMLNSDecl decl = (XMLNSDecl) prefixes.get(i);
1102           boolean shouldExclude = excludeResultNSDecl(decl.getPrefix(),
1103                                                       decl.getURI());
1104 
1105           if (shouldExclude != decl.getIsExcluded())
1106           {
1107             decl = new XMLNSDecl(decl.getPrefix(), decl.getURI(),
1108                                  shouldExclude);
1109           }
1110 
1111           //m_prefixTable.addElement(decl);
1112           addOrReplaceDecls(decl);
1113         }
1114       }
1115     }
1116     else if (null == m_prefixTable)
1117     {
1118 
1119       // Must be stylesheet element without any result prefixes!
1120       setPrefixTable(new ArrayList());
1121     }
1122   }
1123 
1124   /**
1125    * Add or replace this namespace declaration in list
1126    * of namespaces in scope for this element.
1127    *
1128    * @param newDecl namespace declaration to add to list
1129    */
addOrReplaceDecls(XMLNSDecl newDecl)1130   void addOrReplaceDecls(XMLNSDecl newDecl)
1131   {
1132       int n = m_prefixTable.size();
1133 
1134         for (int i = n - 1; i >= 0; i--)
1135         {
1136           XMLNSDecl decl = (XMLNSDecl) m_prefixTable.get(i);
1137 
1138           if (decl.getPrefix().equals(newDecl.getPrefix()))
1139           {
1140             return;
1141           }
1142         }
1143       m_prefixTable.add(newDecl);
1144 
1145   }
1146 
1147   /**
1148    * Return whether we need to check namespace prefixes
1149    * against and exclude result prefixes list.
1150    */
needToCheckExclude()1151   boolean needToCheckExclude()
1152   {
1153     return false;
1154   }
1155 
1156   /**
1157    * Send startPrefixMapping events to the result tree handler
1158    * for all declared prefix mappings in the stylesheet.
1159    *
1160    * @param transformer non-null reference to the the current transform-time state.
1161    *
1162    * @throws TransformerException
1163    */
executeNSDecls(TransformerImpl transformer)1164   void executeNSDecls(TransformerImpl transformer) throws TransformerException
1165   {
1166        executeNSDecls(transformer, null);
1167   }
1168 
1169   /**
1170    * Send startPrefixMapping events to the result tree handler
1171    * for all declared prefix mappings in the stylesheet.
1172    *
1173    * @param transformer non-null reference to the the current transform-time state.
1174    * @param ignorePrefix string prefix to not startPrefixMapping
1175    *
1176    * @throws TransformerException
1177    */
executeNSDecls(TransformerImpl transformer, String ignorePrefix)1178   void executeNSDecls(TransformerImpl transformer, String ignorePrefix) throws TransformerException
1179   {
1180     try
1181     {
1182       if (null != m_prefixTable)
1183       {
1184         SerializationHandler rhandler = transformer.getResultTreeHandler();
1185         int n = m_prefixTable.size();
1186 
1187         for (int i = n - 1; i >= 0; i--)
1188         {
1189           XMLNSDecl decl = (XMLNSDecl) m_prefixTable.get(i);
1190 
1191           if (!decl.getIsExcluded() && !(null != ignorePrefix && decl.getPrefix().equals(ignorePrefix)))
1192           {
1193             rhandler.startPrefixMapping(decl.getPrefix(), decl.getURI(), true);
1194           }
1195         }
1196       }
1197     }
1198     catch(org.xml.sax.SAXException se)
1199     {
1200       throw new TransformerException(se);
1201     }
1202   }
1203 
1204   /**
1205    * Send endPrefixMapping events to the result tree handler
1206    * for all declared prefix mappings in the stylesheet.
1207    *
1208    * @param transformer non-null reference to the the current transform-time state.
1209    *
1210    * @throws TransformerException
1211    */
unexecuteNSDecls(TransformerImpl transformer)1212   void unexecuteNSDecls(TransformerImpl transformer) throws TransformerException
1213   {
1214        unexecuteNSDecls(transformer, null);
1215   }
1216 
1217   /**
1218    * Send endPrefixMapping events to the result tree handler
1219    * for all declared prefix mappings in the stylesheet.
1220    *
1221    * @param transformer non-null reference to the the current transform-time state.
1222    * @param ignorePrefix string prefix to not endPrefixMapping
1223    *
1224    * @throws TransformerException
1225    */
unexecuteNSDecls(TransformerImpl transformer, String ignorePrefix)1226   void unexecuteNSDecls(TransformerImpl transformer, String ignorePrefix) throws TransformerException
1227   {
1228 
1229     try
1230     {
1231       if (null != m_prefixTable)
1232       {
1233         SerializationHandler rhandler = transformer.getResultTreeHandler();
1234         int n = m_prefixTable.size();
1235 
1236         for (int i = 0; i < n; i++)
1237         {
1238           XMLNSDecl decl = (XMLNSDecl) m_prefixTable.get(i);
1239 
1240           if (!decl.getIsExcluded() && !(null != ignorePrefix && decl.getPrefix().equals(ignorePrefix)))
1241           {
1242             rhandler.endPrefixMapping(decl.getPrefix());
1243           }
1244         }
1245       }
1246     }
1247     catch(org.xml.sax.SAXException se)
1248     {
1249       throw new TransformerException(se);
1250     }
1251   }
1252 
1253   /** The *relative* document order number of this element.
1254    *  @serial */
1255   protected int m_docOrderNumber = -1;
1256 
1257   /**
1258    * Set the UID (document order index).
1259    *
1260    * @param i Index of this child.
1261    */
setUid(int i)1262   public void setUid(int i)
1263   {
1264     m_docOrderNumber = i;
1265   }
1266 
1267   /**
1268    * Get the UID (document order index).
1269    *
1270    * @return Index of this child
1271    */
getUid()1272   public int getUid()
1273   {
1274     return m_docOrderNumber;
1275   }
1276 
1277 
1278   /**
1279    * Parent node.
1280    * @serial
1281    */
1282   protected ElemTemplateElement m_parentNode;
1283 
1284   /**
1285    * Get the parent as a Node.
1286    *
1287    * @return This node's parent node
1288    */
getParentNode()1289   public Node getParentNode()
1290   {
1291     return m_parentNode;
1292   }
1293 
1294   /**
1295    * Get the parent as an ElemTemplateElement.
1296    *
1297    * @return This node's parent as an ElemTemplateElement
1298    */
getParentElem()1299   public ElemTemplateElement getParentElem()
1300   {
1301     return m_parentNode;
1302   }
1303 
1304   /**
1305    * Set the parent as an ElemTemplateElement.
1306    *
1307    * @param p This node's parent as an ElemTemplateElement
1308    */
setParentElem(ElemTemplateElement p)1309   public void setParentElem(ElemTemplateElement p)
1310   {
1311     m_parentNode = p;
1312   }
1313 
1314   /**
1315    * Next sibling.
1316    * @serial
1317    */
1318   ElemTemplateElement m_nextSibling;
1319 
1320   /**
1321    * Get the next sibling (as a Node) or return null.
1322    *
1323    * @return this node's next sibling or null
1324    */
getNextSibling()1325   public Node getNextSibling()
1326   {
1327     return m_nextSibling;
1328   }
1329 
1330   /**
1331    * Get the previous sibling (as a Node) or return null.
1332    * Note that this may be expensive if the parent has many kids;
1333    * we accept that price in exchange for avoiding the prev pointer
1334    * TODO: If we were sure parents and sibs are always ElemTemplateElements,
1335    * we could hit the fields directly rather than thru accessors.
1336    *
1337    * @return This node's previous sibling or null
1338    */
getPreviousSibling()1339   public Node getPreviousSibling()
1340   {
1341 
1342     Node walker = getParentNode(), prev = null;
1343 
1344     if (walker != null)
1345       for (walker = walker.getFirstChild(); walker != null;
1346               prev = walker, walker = walker.getNextSibling())
1347       {
1348         if (walker == this)
1349           return prev;
1350       }
1351 
1352     return null;
1353   }
1354 
1355   /**
1356    * Get the previous sibling (as a Node) or return null.
1357    * Note that this may be expensive if the parent has many kids;
1358    * we accept that price in exchange for avoiding the prev pointer
1359    * TODO: If we were sure parents and sibs are always ElemTemplateElements,
1360    * we could hit the fields directly rather than thru accessors.
1361    *
1362    * @return This node's previous sibling or null
1363    */
getPreviousSiblingElem()1364   public ElemTemplateElement getPreviousSiblingElem()
1365   {
1366 
1367     ElemTemplateElement walker = getParentNodeElem();
1368     ElemTemplateElement prev = null;
1369 
1370     if (walker != null)
1371       for (walker = walker.getFirstChildElem(); walker != null;
1372               prev = walker, walker = walker.getNextSiblingElem())
1373       {
1374         if (walker == this)
1375           return prev;
1376       }
1377 
1378     return null;
1379   }
1380 
1381 
1382   /**
1383    * Get the next sibling (as a ElemTemplateElement) or return null.
1384    *
1385    * @return This node's next sibling (as a ElemTemplateElement) or null
1386    */
getNextSiblingElem()1387   public ElemTemplateElement getNextSiblingElem()
1388   {
1389     return m_nextSibling;
1390   }
1391 
1392   /**
1393    * Get the parent element.
1394    *
1395    * @return This node's next parent (as a ElemTemplateElement) or null
1396    */
getParentNodeElem()1397   public ElemTemplateElement getParentNodeElem()
1398   {
1399     return m_parentNode;
1400   }
1401 
1402 
1403   /**
1404    * First child.
1405    * @serial
1406    */
1407   ElemTemplateElement m_firstChild;
1408 
1409   /**
1410    * Get the first child as a Node.
1411    *
1412    * @return This node's first child or null
1413    */
getFirstChild()1414   public Node getFirstChild()
1415   {
1416     return m_firstChild;
1417   }
1418 
1419   /**
1420    * Get the first child as a ElemTemplateElement.
1421    *
1422    * @return This node's first child (as a ElemTemplateElement) or null
1423    */
getFirstChildElem()1424   public ElemTemplateElement getFirstChildElem()
1425   {
1426     return m_firstChild;
1427   }
1428 
1429   /**
1430    * Get the last child.
1431    *
1432    * @return This node's last child
1433    */
getLastChild()1434   public Node getLastChild()
1435   {
1436 
1437     ElemTemplateElement lastChild = null;
1438 
1439     for (ElemTemplateElement node = m_firstChild; node != null;
1440             node = node.m_nextSibling)
1441     {
1442       lastChild = node;
1443     }
1444 
1445     return lastChild;
1446   }
1447 
1448   /**
1449    * Get the last child.
1450    *
1451    * @return This node's last child
1452    */
getLastChildElem()1453   public ElemTemplateElement getLastChildElem()
1454   {
1455 
1456     ElemTemplateElement lastChild = null;
1457 
1458     for (ElemTemplateElement node = m_firstChild; node != null;
1459             node = node.m_nextSibling)
1460     {
1461       lastChild = node;
1462     }
1463 
1464     return lastChild;
1465   }
1466 
1467 
1468   /** DOM backpointer that this element originated from.          */
1469   transient private org.w3c.dom.Node m_DOMBackPointer;
1470 
1471   /**
1472    * If this stylesheet was created from a DOM, get the
1473    * DOM backpointer that this element originated from.
1474    * For tooling use.
1475    *
1476    * @return DOM backpointer that this element originated from or null.
1477    */
getDOMBackPointer()1478   public org.w3c.dom.Node getDOMBackPointer()
1479   {
1480     return m_DOMBackPointer;
1481   }
1482 
1483   /**
1484    * If this stylesheet was created from a DOM, set the
1485    * DOM backpointer that this element originated from.
1486    * For tooling use.
1487    *
1488    * @param n DOM backpointer that this element originated from.
1489    */
setDOMBackPointer(org.w3c.dom.Node n)1490   public void setDOMBackPointer(org.w3c.dom.Node n)
1491   {
1492     m_DOMBackPointer = n;
1493   }
1494 
1495   /**
1496    * Compares this object with the specified object for precedence order.
1497    * The order is determined by the getImportCountComposed() of the containing
1498    * composed stylesheet and the getUid() of this element.
1499    * Returns a negative integer, zero, or a positive integer as this
1500    * object is less than, equal to, or greater than the specified object.
1501    *
1502    * @param o The object to be compared to this object
1503    * @return  a negative integer, zero, or a positive integer as this object is
1504    *          less than, equal to, or greater than the specified object.
1505    * @throws ClassCastException if the specified object's
1506    *         type prevents it from being compared to this Object.
1507    */
compareTo(Object o)1508   public int compareTo(Object o) throws ClassCastException {
1509 
1510     ElemTemplateElement ro = (ElemTemplateElement) o;
1511     int roPrecedence = ro.getStylesheetComposed().getImportCountComposed();
1512     int myPrecedence = this.getStylesheetComposed().getImportCountComposed();
1513 
1514     if (myPrecedence < roPrecedence)
1515       return -1;
1516     else if (myPrecedence > roPrecedence)
1517       return 1;
1518     else
1519       return this.getUid() - ro.getUid();
1520   }
1521 
1522   /**
1523    * Get information about whether or not an element should strip whitespace.
1524    * @see <a href="http://www.w3.org/TR/xslt#strip">strip in XSLT Specification</a>
1525    *
1526    * @param support The XPath runtime state.
1527    * @param targetElement Element to check
1528    *
1529    * @return true if the whitespace should be stripped.
1530    *
1531    * @throws TransformerException
1532    */
shouldStripWhiteSpace( org.apache.xpath.XPathContext support, org.w3c.dom.Element targetElement)1533   public boolean shouldStripWhiteSpace(
1534           org.apache.xpath.XPathContext support,
1535           org.w3c.dom.Element targetElement) throws TransformerException
1536   {
1537     StylesheetRoot sroot = this.getStylesheetRoot();
1538     return (null != sroot) ? sroot.shouldStripWhiteSpace(support, targetElement) :false;
1539   }
1540 
1541   /**
1542    * Get information about whether or not whitespace can be stripped.
1543    * @see <a href="http://www.w3.org/TR/xslt#strip">strip in XSLT Specification</a>
1544    *
1545    * @return true if the whitespace can be stripped.
1546    */
canStripWhiteSpace()1547   public boolean canStripWhiteSpace()
1548   {
1549     StylesheetRoot sroot = this.getStylesheetRoot();
1550     return (null != sroot) ? sroot.canStripWhiteSpace() : false;
1551   }
1552 
1553   /**
1554    * Tell if this element can accept variable declarations.
1555    * @return true if the element can accept and process variable declarations.
1556    */
canAcceptVariables()1557   public boolean canAcceptVariables()
1558   {
1559   	return true;
1560   }
1561 
1562   //=============== ExpressionNode methods ================
1563 
1564   /**
1565    * Set the parent of this node.
1566    * @param n Must be a ElemTemplateElement.
1567    */
exprSetParent(ExpressionNode n)1568   public void exprSetParent(ExpressionNode n)
1569   {
1570   	// This obviously requires that only a ElemTemplateElement can
1571   	// parent a node of this type.
1572   	setParentElem((ElemTemplateElement)n);
1573   }
1574 
1575   /**
1576    * Get the ExpressionNode parent of this node.
1577    */
exprGetParent()1578   public ExpressionNode exprGetParent()
1579   {
1580   	return getParentElem();
1581   }
1582 
1583   /**
1584    * This method tells the node to add its argument to the node's
1585    * list of children.
1586    * @param n Must be a ElemTemplateElement.
1587    */
exprAddChild(ExpressionNode n, int i)1588   public void exprAddChild(ExpressionNode n, int i)
1589   {
1590   	appendChild((ElemTemplateElement)n);
1591   }
1592 
1593   /** This method returns a child node.  The children are numbered
1594      from zero, left to right. */
exprGetChild(int i)1595   public ExpressionNode exprGetChild(int i)
1596   {
1597   	return (ExpressionNode)item(i);
1598   }
1599 
1600   /** Return the number of children the node has. */
exprGetNumChildren()1601   public int exprGetNumChildren()
1602   {
1603   	return getLength();
1604   }
1605 
1606   /**
1607    * Accept a visitor and call the appropriate method
1608    * for this class.
1609    *
1610    * @param visitor The visitor whose appropriate method will be called.
1611    * @return true if the children of the object should be visited.
1612    */
accept(XSLTVisitor visitor)1613   protected boolean accept(XSLTVisitor visitor)
1614   {
1615   	return visitor.visitInstruction(this);
1616   }
1617 
1618   /**
1619    * @see XSLTVisitable#callVisitors(XSLTVisitor)
1620    */
callVisitors(XSLTVisitor visitor)1621   public void callVisitors(XSLTVisitor visitor)
1622   {
1623   	if(accept(visitor))
1624   	{
1625 		callChildVisitors(visitor);
1626   	}
1627   }
1628 
1629   /**
1630    * Call the children visitors.
1631    * @param visitor The visitor whose appropriate method will be called.
1632    */
callChildVisitors(XSLTVisitor visitor, boolean callAttributes)1633   protected void callChildVisitors(XSLTVisitor visitor, boolean callAttributes)
1634   {
1635     for (ElemTemplateElement node = m_firstChild;
1636       node != null;
1637       node = node.m_nextSibling)
1638       {
1639       node.callVisitors(visitor);
1640     }
1641   }
1642 
1643   /**
1644    * Call the children visitors.
1645    * @param visitor The visitor whose appropriate method will be called.
1646    */
callChildVisitors(XSLTVisitor visitor)1647   protected void callChildVisitors(XSLTVisitor visitor)
1648   {
1649   	callChildVisitors(visitor, true);
1650   }
1651 
1652 
1653 	/**
1654 	 * @see PrefixResolver#handlesNullPrefixes()
1655 	 */
handlesNullPrefixes()1656 	public boolean handlesNullPrefixes() {
1657 		return false;
1658 	}
1659 
1660 }
1661