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