Home | History | Annotate | Download | only in templates
      1 /*
      2  * Licensed to the Apache Software Foundation (ASF) under one
      3  * or more contributor license agreements. See the NOTICE file
      4  * distributed with this work for additional information
      5  * regarding copyright ownership. The ASF licenses this file
      6  * to you under the Apache License, Version 2.0 (the  "License");
      7  * you may not use this file except in compliance with the License.
      8  * You may obtain a copy of the License at
      9  *
     10  *     http://www.apache.org/licenses/LICENSE-2.0
     11  *
     12  * Unless required by applicable law or agreed to in writing, software
     13  * distributed under the License is distributed on an "AS IS" BASIS,
     14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15  * See the License for the specific language governing permissions and
     16  * limitations under the License.
     17  */
     18 /*
     19  * $Id: 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    */
     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    */
     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    */
     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    */
     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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    620   public boolean hasTextLitOnly()
    621   {
    622     return m_hasTextLitOnly;
    623   }
    624 
    625   /**
    626    * Return the base identifier.
    627    *
    628    * @return The base identifier
    629    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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 
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    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    */
    961   List getPrefixTable()
    962   {
    963     return m_prefixTable;
    964   }
    965 
    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    */
    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    */
   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    */
   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    */
   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    */
   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    */
   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    */
   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    */
   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    */
   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    */
   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    */
   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    */
   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    */
   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    */
   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    */
   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    */
   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    */
   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    */
   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    */
   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    */
   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    */
   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    */
   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    */
   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    */
   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    */
   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    */
   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    */
   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    */
   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    */
   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    */
   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    */
   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    */
   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. */
   1595   public ExpressionNode exprGetChild(int i)
   1596   {
   1597   	return (ExpressionNode)item(i);
   1598   }
   1599 
   1600   /** Return the number of children the node has. */
   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    */
   1613   protected boolean accept(XSLTVisitor visitor)
   1614   {
   1615   	return visitor.visitInstruction(this);
   1616   }
   1617 
   1618   /**
   1619    * @see XSLTVisitable#callVisitors(XSLTVisitor)
   1620    */
   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    */
   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    */
   1647   protected void callChildVisitors(XSLTVisitor visitor)
   1648   {
   1649   	callChildVisitors(visitor, true);
   1650   }
   1651 
   1652 
   1653 	/**
   1654 	 * @see PrefixResolver#handlesNullPrefixes()
   1655 	 */
   1656 	public boolean handlesNullPrefixes() {
   1657 		return false;
   1658 	}
   1659 
   1660 }
   1661