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 org.w3c.dom.*;
  59. import org.apache.xml.dtm.DTM;
  60. import org.xml.sax.*;
  61. import org.xml.sax.helpers.*;
  62. import java.util.StringTokenizer;
  63. import org.apache.xml.utils.QName;
  64. import org.apache.xml.utils.NameSpace;
  65. import org.apache.xpath.XPathContext;
  66. import org.apache.xml.utils.StringToStringTable;
  67. import org.apache.xml.utils.NameSpace;
  68. import org.apache.xml.utils.StringVector;
  69. import org.apache.xalan.res.XSLTErrorResources;
  70. import org.apache.xalan.transformer.TransformerImpl;
  71. import org.apache.xalan.transformer.ResultTreeHandler;
  72. import javax.xml.transform.TransformerException;
  73. import java.io.*;
  74. import java.util.*;
  75. /**
  76. * <meta name="usage" content="advanced"/>
  77. * Implement a Literal Result Element.
  78. * @see <a href="http://www.w3.org/TR/xslt#literal-result-element">literal-result-element in XSLT Specification</a>
  79. */
  80. public class ElemLiteralResult extends ElemUse
  81. {
  82. /**
  83. * Tells if this element represents a root element
  84. * that is also the stylesheet element.
  85. * TODO: This should be a derived class.
  86. * @serial
  87. */
  88. private boolean isLiteralResultAsStylesheet = false;
  89. /**
  90. * Set whether this element represents a root element
  91. * that is also the stylesheet element.
  92. *
  93. *
  94. * @param b boolean flag indicating whether this element
  95. * represents a root element that is also the stylesheet element.
  96. */
  97. public void setIsLiteralResultAsStylesheet(boolean b)
  98. {
  99. isLiteralResultAsStylesheet = b;
  100. }
  101. /**
  102. * Return whether this element represents a root element
  103. * that is also the stylesheet element.
  104. *
  105. *
  106. * @return boolean flag indicating whether this element
  107. * represents a root element that is also the stylesheet element.
  108. */
  109. public boolean getIsLiteralResultAsStylesheet()
  110. {
  111. return isLiteralResultAsStylesheet;
  112. }
  113. /**
  114. * This function is called after everything else has been
  115. * recomposed, and allows the template to set remaining
  116. * values that may be based on some other property that
  117. * depends on recomposition.
  118. */
  119. public void compose(StylesheetRoot sroot) throws TransformerException
  120. {
  121. super.compose(sroot);
  122. StylesheetRoot.ComposeState cstate = sroot.getComposeState();
  123. java.util.Vector vnames = cstate.getVariableNames();
  124. if (null != m_avts)
  125. {
  126. int nAttrs = m_avts.size();
  127. for (int i = (nAttrs - 1); i >= 0; i--)
  128. {
  129. AVT avt = (AVT) m_avts.elementAt(i);
  130. avt.fixupVariables(vnames, cstate.getGlobalsSize());
  131. }
  132. }
  133. }
  134. /**
  135. * The created element node will have the attribute nodes
  136. * that were present on the element node in the stylesheet tree,
  137. * other than attributes with names in the XSLT namespace.
  138. * @serial
  139. */
  140. private Vector m_avts = null;
  141. /** List of attributes with the XSLT namespace.
  142. * @serial */
  143. private Vector m_xslAttr = null;
  144. /**
  145. * Set a literal result attribute (AVTs only).
  146. *
  147. * @param avt literal result attribute to add (AVT only)
  148. */
  149. public void addLiteralResultAttribute(AVT avt)
  150. {
  151. if (null == m_avts)
  152. m_avts = new Vector();
  153. m_avts.addElement(avt);
  154. }
  155. /**
  156. * Set a literal result attribute (used for xsl attributes).
  157. *
  158. * @param att literal result attribute to add
  159. */
  160. public void addLiteralResultAttribute(String att)
  161. {
  162. if (null == m_xslAttr)
  163. m_xslAttr = new Vector();
  164. m_xslAttr.addElement(att);
  165. }
  166. /**
  167. * Set the "xml:space" attribute.
  168. * A text node is preserved if an ancestor element of the text node
  169. * has an xml:space attribute with a value of preserve, and
  170. * no closer ancestor element has xml:space with a value of default.
  171. * @see <a href="http://www.w3.org/TR/xslt#strip">strip in XSLT Specification</a>
  172. * @see <a href="http://www.w3.org/TR/xslt#section-Creating-Text">section-Creating-Text in XSLT Specification</a>
  173. *
  174. * @param v Enumerated value, either Constants.ATTRVAL_PRESERVE
  175. * or Constants.ATTRVAL_STRIP.
  176. */
  177. public void setXmlSpace(AVT avt)
  178. {
  179. // This function is a bit-o-hack, I guess...
  180. addLiteralResultAttribute(avt);
  181. String val = avt.getSimpleString();
  182. if(val.equals("default"))
  183. {
  184. super.setXmlSpace(Constants.ATTRVAL_STRIP);
  185. }
  186. else if(val.equals("preserve"))
  187. {
  188. super.setXmlSpace(Constants.ATTRVAL_PRESERVE);
  189. }
  190. // else maybe it's a real AVT, so we can't resolve it at this time.
  191. }
  192. /**
  193. * Get a literal result attribute by name.
  194. *
  195. * @param name Name of literal result attribute to get
  196. *
  197. * @return literal result attribute (AVT)
  198. */
  199. public AVT getLiteralResultAttribute(String name)
  200. {
  201. if (null != m_avts)
  202. {
  203. int nAttrs = m_avts.size();
  204. for (int i = (nAttrs - 1); i >= 0; i--)
  205. {
  206. AVT avt = (AVT) m_avts.elementAt(i);
  207. if (avt.getRawName().equals(name))
  208. {
  209. return avt;
  210. }
  211. } // end for
  212. }
  213. return null;
  214. }
  215. /**
  216. * Get whether or not the passed URL is flagged by
  217. * the "extension-element-prefixes" or "exclude-result-prefixes"
  218. * properties.
  219. * @see <a href="http://www.w3.org/TR/xslt#extension-element">extension-element in XSLT Specification</a>
  220. *
  221. * @param prefix non-null reference to prefix that might be excluded.(not currently used)
  222. * @param uri reference to namespace that prefix maps to
  223. *
  224. * @return true if the prefix should normally be excluded.
  225. */
  226. public boolean containsExcludeResultPrefix(String prefix, String uri)
  227. {
  228. if (uri == null ||
  229. (null == m_excludeResultPrefixes &&
  230. null == m_ExtensionElementURIs)
  231. )
  232. return super.containsExcludeResultPrefix(prefix, uri);
  233. if (prefix.length() == 0)
  234. prefix = Constants.ATTRVAL_DEFAULT_PREFIX;
  235. // This loop is ok here because this code only runs during
  236. // stylesheet compile time.
  237. if(m_excludeResultPrefixes!=null)
  238. for (int i =0; i< m_excludeResultPrefixes.size(); i++)
  239. {
  240. if (uri.equals(getNamespaceForPrefix(m_excludeResultPrefixes.elementAt(i))))
  241. return true;
  242. }
  243. // JJK Bugzilla 1133: Also check locally-scoped extensions
  244. if(m_ExtensionElementURIs!=null && m_ExtensionElementURIs.contains(uri))
  245. return true;
  246. return super.containsExcludeResultPrefix(prefix, uri);
  247. }
  248. /**
  249. * Augment resolvePrefixTables, resolving the namespace aliases once
  250. * the superclass has resolved the tables.
  251. *
  252. * @throws TransformerException
  253. */
  254. public void resolvePrefixTables() throws TransformerException
  255. {
  256. super.resolvePrefixTables();
  257. StylesheetRoot stylesheet = getStylesheetRoot();
  258. if ((null != m_namespace) && (m_namespace.length() > 0))
  259. {
  260. NamespaceAlias nsa = stylesheet.getNamespaceAliasComposed(m_namespace);
  261. if (null != nsa)
  262. {
  263. m_namespace = nsa.getResultNamespace();
  264. // String resultPrefix = nsa.getResultPrefix();
  265. String resultPrefix = nsa.getStylesheetPrefix(); // As per xsl WG, Mike Kay
  266. if ((null != resultPrefix) && (resultPrefix.length() > 0))
  267. m_rawName = resultPrefix + ":" + m_localName;
  268. else
  269. m_rawName = m_localName;
  270. }
  271. }
  272. if (null != m_avts)
  273. {
  274. int n = m_avts.size();
  275. for (int i = 0; i < n; i++)
  276. {
  277. AVT avt = (AVT) m_avts.elementAt(i);
  278. // Should this stuff be a method on AVT?
  279. String ns = avt.getURI();
  280. if ((null != ns) && (ns.length() > 0))
  281. {
  282. NamespaceAlias nsa =
  283. stylesheet.getNamespaceAliasComposed(m_namespace); // %REVIEW% ns?
  284. if (null != nsa)
  285. {
  286. String namespace = nsa.getResultNamespace();
  287. // String resultPrefix = nsa.getResultPrefix();
  288. String resultPrefix = nsa.getStylesheetPrefix(); // As per XSL WG
  289. String rawName = avt.getName();
  290. if ((null != resultPrefix) && (resultPrefix.length() > 0))
  291. rawName = resultPrefix + ":" + rawName;
  292. avt.setURI(namespace);
  293. avt.setRawName(rawName);
  294. }
  295. }
  296. }
  297. }
  298. }
  299. /**
  300. * Return whether we need to check namespace prefixes
  301. * against the exclude result prefixes or extensions lists.
  302. * Note that this will create a new prefix table if one
  303. * has not been created already.
  304. *
  305. * NEEDSDOC ($objectName$) @return
  306. */
  307. boolean needToCheckExclude()
  308. {
  309. if (null == m_excludeResultPrefixes && null == m_prefixTable
  310. && m_ExtensionElementURIs==null // JJK Bugzilla 1133
  311. )
  312. return false;
  313. else
  314. {
  315. // Create a new prefix table if one has not already been created.
  316. if (null == m_prefixTable)
  317. m_prefixTable = new Vector();
  318. return true;
  319. }
  320. }
  321. /**
  322. * The namespace of the element to be created.
  323. * @serial
  324. */
  325. private String m_namespace;
  326. /**
  327. * Set the namespace URI of the result element to be created.
  328. * Note that after resolvePrefixTables has been called, this will
  329. * return the aliased result namespace, not the original stylesheet
  330. * namespace.
  331. *
  332. * @param ns The Namespace URI, or the empty string if the
  333. * element has no Namespace URI.
  334. */
  335. public void setNamespace(String ns)
  336. {
  337. if(null == ns) // defensive, shouldn't have to do this.
  338. ns = "";
  339. m_namespace = ns;
  340. }
  341. /**
  342. * Get the original namespace of the Literal Result Element.
  343. *
  344. * %REVIEW% Why isn't this overriding the getNamespaceURI method
  345. * rather than introducing a new one?
  346. *
  347. * @return The Namespace URI, or the empty string if the
  348. * element has no Namespace URI.
  349. */
  350. public String getNamespace()
  351. {
  352. return m_namespace;
  353. }
  354. /**
  355. * The local name of the element to be created.
  356. * @serial
  357. */
  358. private String m_localName;
  359. /**
  360. * Set the local name of the LRE.
  361. *
  362. * @param localName The local name (without prefix) of the result element
  363. * to be created.
  364. */
  365. public void setLocalName(String localName)
  366. {
  367. m_localName = localName;
  368. }
  369. /**
  370. * Get the local name of the Literal Result Element.
  371. * Note that after resolvePrefixTables has been called, this will
  372. * return the aliased name prefix, not the original stylesheet
  373. * namespace prefix.
  374. *
  375. * @return The local name (without prefix) of the result element
  376. * to be created.
  377. */
  378. public String getLocalName()
  379. {
  380. return m_localName;
  381. }
  382. /**
  383. * The raw name of the element to be created.
  384. * @serial
  385. */
  386. private String m_rawName;
  387. /**
  388. * Set the raw name of the LRE.
  389. *
  390. * @param rawName The qualified name (with prefix), or the
  391. * empty string if qualified names are not available.
  392. */
  393. public void setRawName(String rawName)
  394. {
  395. m_rawName = rawName;
  396. }
  397. /**
  398. * Get the raw name of the Literal Result Element.
  399. *
  400. * @return The qualified name (with prefix), or the
  401. * empty string if qualified names are not available.
  402. */
  403. public String getRawName()
  404. {
  405. return m_rawName;
  406. }
  407. /**
  408. * Get the prefix part of the raw name of the Literal Result Element.
  409. *
  410. * @return The prefix, or the empty string if noprefix was provided.
  411. */
  412. public String getPrefix()
  413. {
  414. int len=m_rawName.length()-m_localName.length()-1;
  415. return (len>0)
  416. ? m_rawName.substring(0,len)
  417. : "";
  418. }
  419. /**
  420. * The "extension-element-prefixes" property, actually contains URIs.
  421. * @serial
  422. */
  423. private StringVector m_ExtensionElementURIs;
  424. /**
  425. * Set the "extension-element-prefixes" property.
  426. * @see <a href="http://www.w3.org/TR/xslt#extension-element">extension-element in XSLT Specification</a>
  427. *
  428. * @param v Vector of URIs (not prefixes) to set as the "extension-element-prefixes" property
  429. */
  430. public void setExtensionElementPrefixes(StringVector v)
  431. {
  432. m_ExtensionElementURIs = v;
  433. }
  434. /**
  435. * Get an "extension-element-prefix" property.
  436. * @see <a href="http://www.w3.org/TR/xslt#extension-element">extension-element in XSLT Specification</a>
  437. *
  438. * @param i Index of URI ("extension-element-prefix" property) to get
  439. *
  440. * @return URI at given index ("extension-element-prefix" property)
  441. *
  442. * @throws ArrayIndexOutOfBoundsException
  443. */
  444. public String getExtensionElementPrefix(int i)
  445. throws ArrayIndexOutOfBoundsException
  446. {
  447. if (null == m_ExtensionElementURIs)
  448. throw new ArrayIndexOutOfBoundsException();
  449. return m_ExtensionElementURIs.elementAt(i);
  450. }
  451. /**
  452. * Get the number of "extension-element-prefixes" Strings.
  453. * @see <a href="http://www.w3.org/TR/xslt#extension-element">extension-element in XSLT Specification</a>
  454. *
  455. * @return the number of "extension-element-prefixes" Strings
  456. */
  457. public int getExtensionElementPrefixCount()
  458. {
  459. return (null != m_ExtensionElementURIs)
  460. ? m_ExtensionElementURIs.size() : 0;
  461. }
  462. /**
  463. * Find out if the given "extension-element-prefix" property is defined.
  464. * @see <a href="http://www.w3.org/TR/xslt#extension-element">extension-element in XSLT Specification</a>
  465. *
  466. * @param uri The URI to find
  467. *
  468. * @return True if the given URI is found
  469. */
  470. public boolean containsExtensionElementURI(String uri)
  471. {
  472. if (null == m_ExtensionElementURIs)
  473. return false;
  474. return m_ExtensionElementURIs.contains(uri);
  475. }
  476. /**
  477. * Get an int constant identifying the type of element.
  478. * @see org.apache.xalan.templates.Constants
  479. *
  480. * @return The token ID for this element
  481. */
  482. public int getXSLToken()
  483. {
  484. return Constants.ELEMNAME_LITERALRESULT;
  485. }
  486. /**
  487. * Return the node name.
  488. *
  489. * @return The element's name
  490. */
  491. public String getNodeName()
  492. {
  493. // TODO: Need prefix.
  494. return m_rawName;
  495. }
  496. /**
  497. * The XSLT version as specified by this element.
  498. * @serial
  499. */
  500. private String m_version;
  501. /**
  502. * Set the "version" property.
  503. * @see <a href="http://www.w3.org/TR/xslt#forwards">forwards in XSLT Specification</a>
  504. *
  505. * @param v Version property value to set
  506. */
  507. public void setVersion(String v)
  508. {
  509. m_version = v;
  510. }
  511. /**
  512. * Get the "version" property.
  513. * @see <a href="http://www.w3.org/TR/xslt#forwards">forwards in XSLT Specification</a>
  514. *
  515. * @return Version property value
  516. */
  517. public String getVersion()
  518. {
  519. return m_version;
  520. }
  521. /**
  522. * The "exclude-result-prefixes" property.
  523. * @serial
  524. */
  525. private StringVector m_excludeResultPrefixes;
  526. /**
  527. * Set the "exclude-result-prefixes" property.
  528. * The designation of a namespace as an excluded namespace is
  529. * effective within the subtree of the stylesheet rooted at
  530. * the element bearing the exclude-result-prefixes or
  531. * xsl:exclude-result-prefixes attribute; a subtree rooted
  532. * at an xsl:stylesheet element does not include any stylesheets
  533. * imported or included by children of that xsl:stylesheet element.
  534. * @see <a href="http://www.w3.org/TR/xslt#literal-result-element">literal-result-element in XSLT Specification</a>
  535. *
  536. * @param v vector of prefixes that are resolvable to strings.
  537. */
  538. public void setExcludeResultPrefixes(StringVector v)
  539. {
  540. m_excludeResultPrefixes = v;
  541. }
  542. /**
  543. * Tell if the result namespace decl should be excluded. Should be called before
  544. * namespace aliasing (I think).
  545. *
  546. * @param prefix Prefix of namespace to check
  547. * @param uri URI of namespace to check
  548. *
  549. * @return True if the given namespace should be excluded
  550. *
  551. * @throws TransformerException
  552. */
  553. private boolean excludeResultNSDecl(String prefix, String uri)
  554. throws TransformerException
  555. {
  556. if (null != m_excludeResultPrefixes)
  557. {
  558. return containsExcludeResultPrefix(prefix, uri);
  559. }
  560. return false;
  561. }
  562. /**
  563. * Copy a Literal Result Element into the Result tree, copy the
  564. * non-excluded namespace attributes, copy the attributes not
  565. * of the XSLT namespace, and execute the children of the LRE.
  566. * @see <a href="http://www.w3.org/TR/xslt#literal-result-element">literal-result-element in XSLT Specification</a>
  567. *
  568. * @param transformer non-null reference to the the current transform-time state.
  569. * @param sourceNode non-null reference to the <a href="http://www.w3.org/TR/xslt#dt-current-node">current source node</a>.
  570. * @param mode reference, which may be null, to the <a href="http://www.w3.org/TR/xslt#modes">current mode</a>.
  571. *
  572. * @throws TransformerException
  573. */
  574. public void execute(
  575. TransformerImpl transformer)
  576. throws TransformerException
  577. {
  578. try
  579. {
  580. ResultTreeHandler rhandler = transformer.getResultTreeHandler();
  581. // JJK Bugzilla 3464, test namespace85 -- make sure LRE's
  582. // namespace is asserted even if default, since xsl:element
  583. // may have changed the context.
  584. rhandler.startPrefixMapping(getPrefix(),getNamespace());
  585. // Add namespace declarations.
  586. executeNSDecls(transformer);
  587. rhandler.startElement(getNamespace(), getLocalName(), getRawName(), null);
  588. try
  589. {
  590. // Process any possible attributes from xsl:use-attribute-sets first
  591. super.execute(transformer);
  592. //xsl:version, excludeResultPrefixes???
  593. // Process the list of avts next
  594. if (null != m_avts)
  595. {
  596. int nAttrs = m_avts.size();
  597. for (int i = (nAttrs - 1); i >= 0; i--)
  598. {
  599. AVT avt = (AVT) m_avts.elementAt(i);
  600. XPathContext xctxt = transformer.getXPathContext();
  601. int sourceNode = xctxt.getCurrentNode();
  602. String stringedValue = avt.evaluate(xctxt, sourceNode, this);
  603. if (null != stringedValue)
  604. {
  605. // Important Note: I'm not going to check for excluded namespace
  606. // prefixes here. It seems like it's too expensive, and I'm not
  607. // even sure this is right. But I could be wrong, so this needs
  608. // to be tested against other implementations.
  609. rhandler.addAttribute(avt.getURI(), avt.getName(),
  610. avt.getRawName(), "CDATA", stringedValue);
  611. }
  612. } // end for
  613. }
  614. // Now process all the elements in this subtree
  615. // TODO: Process m_extensionElementPrefixes && m_attributeSetsNames
  616. transformer.executeChildTemplates(this, true);
  617. }
  618. finally
  619. {
  620. // If you don't do this in a finally statement, an exception could
  621. // cause a system hang.
  622. rhandler.endElement(getNamespace(), getLocalName(), getRawName());
  623. unexecuteNSDecls(transformer);
  624. // JJK Bugzilla 3464, test namespace85 -- balance explicit start.
  625. rhandler.endPrefixMapping(getPrefix());
  626. }
  627. }
  628. catch (org.xml.sax.SAXException se)
  629. {
  630. throw new TransformerException(se);
  631. }
  632. }
  633. /**
  634. * Compiling templates requires that we be able to list the AVTs
  635. * ADDED 9/5/2000 to support compilation experiment
  636. *
  637. * @return an Enumeration of the literal result attributes associated
  638. * with this element.
  639. */
  640. public Enumeration enumerateLiteralResultAttributes()
  641. {
  642. return (null == m_avts) ? null : m_avts.elements();
  643. }
  644. /**
  645. * Accept a visitor and call the appropriate method
  646. * for this class.
  647. *
  648. * @param visitor The visitor whose appropriate method will be called.
  649. * @return true if the children of the object should be visited.
  650. */
  651. protected boolean accept(XSLTVisitor visitor)
  652. {
  653. return visitor.visitLiteralResultElement(this);
  654. }
  655. /**
  656. * Call the children visitors.
  657. * @param visitor The visitor whose appropriate method will be called.
  658. */
  659. protected void callChildVisitors(XSLTVisitor visitor, boolean callAttrs)
  660. {
  661. if (callAttrs && null != m_avts)
  662. {
  663. int nAttrs = m_avts.size();
  664. for (int i = (nAttrs - 1); i >= 0; i--)
  665. {
  666. AVT avt = (AVT) m_avts.elementAt(i);
  667. avt.callVisitors(visitor);
  668. }
  669. }
  670. super.callChildVisitors(visitor, callAttrs);
  671. }
  672. }