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.util.Hashtable;
  59. import java.util.Vector;
  60. import java.util.Enumeration;
  61. import java.io.Serializable;
  62. //import org.w3c.dom.Node;
  63. import org.apache.xml.dtm.DTM;
  64. import org.apache.xml.dtm.ref.ExpandedNameTable;
  65. import javax.xml.transform.TransformerException;
  66. import org.apache.xml.utils.QName;
  67. import org.apache.xml.utils.PrefixResolver;
  68. import org.apache.xpath.XPath;
  69. import org.apache.xpath.compiler.PsuedoNames;
  70. import org.apache.xpath.patterns.NodeTest;
  71. import org.apache.xpath.Expression;
  72. import org.apache.xalan.res.XSLTErrorResources;
  73. import org.apache.xpath.XPathContext;
  74. import org.apache.xpath.patterns.StepPattern;
  75. import org.apache.xpath.patterns.UnionPattern;
  76. /**
  77. * <meta name="usage" content="advanced"/>
  78. * Encapsulates a template list, and helps locate individual templates.
  79. */
  80. public class TemplateList implements java.io.Serializable
  81. {
  82. /**
  83. * Construct a TemplateList object. Needs to be public so it can
  84. * be invoked from the CompilingStylesheetHandler.
  85. */
  86. public TemplateList()
  87. {
  88. super();
  89. }
  90. /**
  91. * Add a template to the table of named templates and/or the table of templates
  92. * with match patterns. This routine should
  93. * be called in decreasing order of precedence but it checks nonetheless.
  94. *
  95. * @param template
  96. */
  97. public void setTemplate(ElemTemplate template)
  98. {
  99. if (null != template.getName())
  100. {
  101. ElemTemplate existingTemplate = (ElemTemplate) m_namedTemplates.get(template.getName());
  102. if (null == existingTemplate)
  103. {
  104. m_namedTemplates.put(template.getName(), template);
  105. }
  106. else
  107. {
  108. int existingPrecedence =
  109. existingTemplate.getStylesheetComposed().getImportCountComposed();
  110. int newPrecedence = template.getStylesheetComposed().getImportCountComposed();
  111. if (newPrecedence > existingPrecedence)
  112. {
  113. // This should never happen
  114. m_namedTemplates.put(template.getName(), template);
  115. }
  116. else if (newPrecedence == existingPrecedence)
  117. template.error(XSLTErrorResources.ER_DUPLICATE_NAMED_TEMPLATE,
  118. new Object[]{ template.getName() });
  119. }
  120. }
  121. XPath matchXPath = template.getMatch();
  122. if (null != matchXPath)
  123. {
  124. Expression matchExpr = matchXPath.getExpression();
  125. if (matchExpr instanceof StepPattern)
  126. {
  127. insertPatternInTable((StepPattern) matchExpr, template);
  128. }
  129. else if (matchExpr instanceof UnionPattern)
  130. {
  131. UnionPattern upat = (UnionPattern) matchExpr;
  132. StepPattern[] pats = upat.getPatterns();
  133. int n = pats.length;
  134. for (int i = 0; i < n; i++)
  135. {
  136. insertPatternInTable(pats[i], template);
  137. }
  138. }
  139. else
  140. {
  141. // TODO: assert error
  142. }
  143. }
  144. }
  145. /** Flag to indicate whether in DEBUG mode */
  146. static boolean DEBUG = false;
  147. /**
  148. * Dump all patterns and elements that match those patterns
  149. *
  150. */
  151. void dumpAssociationTables()
  152. {
  153. Enumeration associations = m_patternTable.elements();
  154. while (associations.hasMoreElements())
  155. {
  156. TemplateSubPatternAssociation head =
  157. (TemplateSubPatternAssociation) associations.nextElement();
  158. while (null != head)
  159. {
  160. System.out.print("(" + head.getTargetString() + ", "
  161. + head.getPattern() + ")");
  162. head = head.getNext();
  163. }
  164. System.out.println("\n.....");
  165. }
  166. TemplateSubPatternAssociation head = m_wildCardPatterns;
  167. System.out.print("wild card list: ");
  168. while (null != head)
  169. {
  170. System.out.print("(" + head.getTargetString() + ", "
  171. + head.getPattern() + ")");
  172. head = head.getNext();
  173. }
  174. System.out.println("\n.....");
  175. }
  176. /**
  177. * After all templates have been added, this function
  178. * should be called.
  179. */
  180. public void compose(StylesheetRoot sroot)
  181. {
  182. if (DEBUG)
  183. {
  184. System.out.println("Before wildcard insert...");
  185. dumpAssociationTables();
  186. }
  187. if (null != m_wildCardPatterns)
  188. {
  189. Enumeration associations = m_patternTable.elements();
  190. while (associations.hasMoreElements())
  191. {
  192. TemplateSubPatternAssociation head =
  193. (TemplateSubPatternAssociation) associations.nextElement();
  194. TemplateSubPatternAssociation wild = m_wildCardPatterns;
  195. while (null != wild)
  196. {
  197. try
  198. {
  199. head = insertAssociationIntoList(
  200. head, (TemplateSubPatternAssociation) wild.clone(), true);
  201. }
  202. catch (CloneNotSupportedException cnse){}
  203. wild = wild.getNext();
  204. }
  205. }
  206. }
  207. if (DEBUG)
  208. {
  209. System.out.println("After wildcard insert...");
  210. dumpAssociationTables();
  211. }
  212. }
  213. /**
  214. * Insert the given TemplateSubPatternAssociation into the the linked
  215. * list. Sort by import precedence, then priority, then by document order.
  216. *
  217. * @param head The first TemplateSubPatternAssociation in the linked list.
  218. * @param item The item that we want to insert into the proper place.
  219. * @param isWildCardInsert <code>true</code> if we are inserting a wild card
  220. * template onto this list.
  221. * @return the new head of the list.
  222. */
  223. private TemplateSubPatternAssociation
  224. insertAssociationIntoList(TemplateSubPatternAssociation head,
  225. TemplateSubPatternAssociation item,
  226. boolean isWildCardInsert)
  227. {
  228. // Sort first by import level (higher level is at front),
  229. // then by priority (highest priority is at front),
  230. // then by document order (later in document is at front).
  231. double priority = getPriorityOrScore(item);
  232. double workPriority;
  233. int importLevel = item.getImportLevel();
  234. int docOrder = item.getDocOrderPos();
  235. TemplateSubPatternAssociation insertPoint = head;
  236. TemplateSubPatternAssociation next;
  237. boolean insertBefore; // true means insert before insertPoint; otherwise after
  238. // This can only be true if insertPoint is pointing to
  239. // the first or last template.
  240. // Spin down so that insertPoint points to:
  241. // (a) the template immediately _before_ the first template on the chain with
  242. // a precedence that is either (i) less than ours or (ii) the same as ours but
  243. // the template document position is less than ours
  244. // -or-
  245. // (b) the last template on the chain if no such template described in (a) exists.
  246. // If we are pointing to the first template or the last template (that is, case b),
  247. // we need to determine whether to insert before or after the template. Otherwise,
  248. // we always insert after the insertPoint.
  249. while (true)
  250. {
  251. next = insertPoint.getNext();
  252. if (null == next)
  253. break;
  254. else
  255. {
  256. workPriority = getPriorityOrScore(next);
  257. if (importLevel > next.getImportLevel())
  258. break;
  259. else if (importLevel < next.getImportLevel())
  260. insertPoint = next;
  261. else if (priority > workPriority) // import precedence is equal
  262. break;
  263. else if (priority < workPriority)
  264. insertPoint = next;
  265. else if (docOrder >= next.getDocOrderPos()) // priorities, import are equal
  266. break;
  267. else
  268. insertPoint = next;
  269. }
  270. }
  271. if ( (null == next) || (insertPoint == head) ) // insert point is first or last
  272. {
  273. workPriority = getPriorityOrScore(insertPoint);
  274. if (importLevel > insertPoint.getImportLevel())
  275. insertBefore = true;
  276. else if (importLevel < insertPoint.getImportLevel())
  277. insertBefore = false;
  278. else if (priority > workPriority)
  279. insertBefore = true;
  280. else if (priority < workPriority)
  281. insertBefore = false;
  282. else if (docOrder >= insertPoint.getDocOrderPos())
  283. insertBefore = true;
  284. else
  285. insertBefore = false;
  286. }
  287. else
  288. insertBefore = false;
  289. // System.out.println("appending: "+target+" to "+matchPat.getPattern());
  290. if (isWildCardInsert)
  291. {
  292. if (insertBefore)
  293. {
  294. item.setNext(insertPoint);
  295. String key = insertPoint.getTargetString();
  296. item.setTargetString(key);
  297. putHead(key, item);
  298. return item;
  299. }
  300. else
  301. {
  302. item.setNext(next);
  303. insertPoint.setNext(item);
  304. return head;
  305. }
  306. }
  307. else
  308. {
  309. if (insertBefore)
  310. {
  311. item.setNext(insertPoint);
  312. if (insertPoint.isWild() || item.isWild())
  313. m_wildCardPatterns = item;
  314. else
  315. putHead(item.getTargetString(), item);
  316. return item;
  317. }
  318. else
  319. {
  320. item.setNext(next);
  321. insertPoint.setNext(item);
  322. return head;
  323. }
  324. }
  325. }
  326. /**
  327. * Add a template to the template list.
  328. *
  329. * @param pattern
  330. * @param template
  331. */
  332. private void insertPatternInTable(StepPattern pattern, ElemTemplate template)
  333. {
  334. String target = pattern.getTargetString();
  335. if (null != target)
  336. {
  337. String pstring = template.getMatch().getPatternString();
  338. TemplateSubPatternAssociation association =
  339. new TemplateSubPatternAssociation(template, pattern, pstring);
  340. // See if there's already one there
  341. boolean isWildCard = association.isWild();
  342. TemplateSubPatternAssociation head = isWildCard
  343. ? m_wildCardPatterns
  344. : getHead(target);
  345. if (null == head)
  346. {
  347. if (isWildCard)
  348. m_wildCardPatterns = association;
  349. else
  350. putHead(target, association);
  351. }
  352. else
  353. {
  354. insertAssociationIntoList(head, association, false);
  355. }
  356. }
  357. }
  358. /**
  359. * Given a match pattern and template association, return the
  360. * score of that match. This score or priority can always be
  361. * statically calculated.
  362. *
  363. * @param matchPat The match pattern to template association.
  364. *
  365. * @return {@link org.apache.xpath.patterns.NodeTest#SCORE_NODETEST},
  366. * {@link org.apache.xpath.patterns.NodeTest#SCORE_NONE},
  367. * {@link org.apache.xpath.patterns.NodeTest#SCORE_NSWILD},
  368. * {@link org.apache.xpath.patterns.NodeTest#SCORE_QNAME}, or
  369. * {@link org.apache.xpath.patterns.NodeTest#SCORE_OTHER}, or
  370. * the value defined by the priority attribute of the template.
  371. *
  372. */
  373. private double getPriorityOrScore(TemplateSubPatternAssociation matchPat)
  374. {
  375. double priority = matchPat.getTemplate().getPriority();
  376. if (priority == XPath.MATCH_SCORE_NONE)
  377. {
  378. Expression ex = matchPat.getStepPattern();
  379. if (ex instanceof NodeTest)
  380. {
  381. return ((NodeTest) ex).getDefaultScore();
  382. }
  383. }
  384. return priority;
  385. }
  386. /**
  387. * Locate a named template.
  388. *
  389. * @param qname Qualified name of the template.
  390. *
  391. * @return Template argument with the requested name, or null if not found.
  392. */
  393. public ElemTemplate getTemplate(QName qname)
  394. {
  395. return (ElemTemplate) m_namedTemplates.get(qname);
  396. }
  397. /**
  398. * Get the head of the most likely list of associations to check, based on
  399. * the name and type of the targetNode argument.
  400. *
  401. * @param xctxt The XPath runtime context.
  402. * @param targetNode The target node that will be checked for a match.
  403. * @param dtm The dtm owner for the target node.
  404. *
  405. * @return The head of a linked list that contains all possible match pattern to
  406. * template associations.
  407. */
  408. public TemplateSubPatternAssociation getHead(XPathContext xctxt,
  409. int targetNode, DTM dtm)
  410. {
  411. short targetNodeType = dtm.getNodeType(targetNode);
  412. TemplateSubPatternAssociation head;
  413. switch (targetNodeType)
  414. {
  415. case DTM.ELEMENT_NODE :
  416. case DTM.ATTRIBUTE_NODE :
  417. head = (TemplateSubPatternAssociation) m_patternTable.get(
  418. dtm.getLocalName(targetNode));
  419. break;
  420. case DTM.TEXT_NODE :
  421. case DTM.CDATA_SECTION_NODE :
  422. head = m_textPatterns;
  423. break;
  424. case DTM.ENTITY_REFERENCE_NODE :
  425. case DTM.ENTITY_NODE :
  426. head = (TemplateSubPatternAssociation) m_patternTable.get(
  427. dtm.getNodeName(targetNode)); // %REVIEW% I think this is right
  428. break;
  429. case DTM.PROCESSING_INSTRUCTION_NODE :
  430. head = (TemplateSubPatternAssociation) m_patternTable.get(
  431. dtm.getLocalName(targetNode));
  432. break;
  433. case DTM.COMMENT_NODE :
  434. head = m_commentPatterns;
  435. break;
  436. case DTM.DOCUMENT_NODE :
  437. case DTM.DOCUMENT_FRAGMENT_NODE :
  438. head = m_docPatterns;
  439. break;
  440. case DTM.NOTATION_NODE :
  441. default :
  442. head = (TemplateSubPatternAssociation) m_patternTable.get(
  443. dtm.getNodeName(targetNode)); // %REVIEW% I think this is right
  444. }
  445. return (null == head) ? m_wildCardPatterns : head;
  446. }
  447. /**
  448. * Given a target element, find the template that best
  449. * matches in the given XSL document, according
  450. * to the rules specified in the xsl draft. This variation of getTemplate
  451. * assumes the current node and current expression node have already been
  452. * pushed.
  453. *
  454. * @param xctxt
  455. * @param targetNode
  456. * @param mode A string indicating the display mode.
  457. * @param maxImportLevel The maximum importCountComposed that we should consider or -1
  458. * if we should consider all import levels. This is used by apply-imports to
  459. * access templates that have been overridden.
  460. * @param quietConflictWarnings
  461. * @return Rule that best matches targetElem.
  462. * @throws XSLProcessorException thrown if the active ProblemListener and XPathContext decide
  463. * the error condition is severe enough to halt processing.
  464. *
  465. * @throws TransformerException
  466. */
  467. public ElemTemplate getTemplateFast(XPathContext xctxt,
  468. int targetNode,
  469. int expTypeID,
  470. QName mode,
  471. int maxImportLevel,
  472. boolean quietConflictWarnings,
  473. DTM dtm)
  474. throws TransformerException
  475. {
  476. TemplateSubPatternAssociation head;
  477. switch (dtm.getNodeType(targetNode))
  478. {
  479. case DTM.ELEMENT_NODE :
  480. case DTM.ATTRIBUTE_NODE :
  481. head = (TemplateSubPatternAssociation) m_patternTable.get(
  482. dtm.getLocalNameFromExpandedNameID(expTypeID));
  483. break;
  484. case DTM.TEXT_NODE :
  485. case DTM.CDATA_SECTION_NODE :
  486. head = m_textPatterns;
  487. break;
  488. case DTM.ENTITY_REFERENCE_NODE :
  489. case DTM.ENTITY_NODE :
  490. head = (TemplateSubPatternAssociation) m_patternTable.get(
  491. dtm.getNodeName(targetNode)); // %REVIEW% I think this is right
  492. break;
  493. case DTM.PROCESSING_INSTRUCTION_NODE :
  494. head = (TemplateSubPatternAssociation) m_patternTable.get(
  495. dtm.getLocalName(targetNode));
  496. break;
  497. case DTM.COMMENT_NODE :
  498. head = m_commentPatterns;
  499. break;
  500. case DTM.DOCUMENT_NODE :
  501. case DTM.DOCUMENT_FRAGMENT_NODE :
  502. head = m_docPatterns;
  503. break;
  504. case DTM.NOTATION_NODE :
  505. default :
  506. head = (TemplateSubPatternAssociation) m_patternTable.get(
  507. dtm.getNodeName(targetNode)); // %REVIEW% I think this is right
  508. }
  509. if(null == head)
  510. {
  511. head = m_wildCardPatterns;
  512. if(null == head)
  513. return null;
  514. }
  515. // XSLT functions, such as xsl:key, need to be able to get to
  516. // current ElemTemplateElement via a cast to the prefix resolver.
  517. // Setting this fixes bug idkey03.
  518. xctxt.pushNamespaceContextNull();
  519. try
  520. {
  521. do
  522. {
  523. if ( (maxImportLevel > -1) && (head.getImportLevel() > maxImportLevel) )
  524. {
  525. continue;
  526. }
  527. ElemTemplate template = head.getTemplate();
  528. xctxt.setNamespaceContext(template);
  529. if ((head.m_stepPattern.execute(xctxt, targetNode, dtm, expTypeID) != NodeTest.SCORE_NONE)
  530. && head.matchMode(mode))
  531. {
  532. if (quietConflictWarnings)
  533. checkConflicts(head, xctxt, targetNode, mode);
  534. return template;
  535. }
  536. }
  537. while (null != (head = head.getNext()));
  538. }
  539. finally
  540. {
  541. xctxt.popNamespaceContext();
  542. }
  543. return null;
  544. } // end findTemplate
  545. /**
  546. * Given a target element, find the template that best
  547. * matches in the given XSL document, according
  548. * to the rules specified in the xsl draft.
  549. *
  550. * @param xctxt
  551. * @param targetNode
  552. * @param mode A string indicating the display mode.
  553. * @param quietConflictWarnings
  554. * @return Rule that best matches targetElem.
  555. * @throws XSLProcessorException thrown if the active ProblemListener and XPathContext decide
  556. * the error condition is severe enough to halt processing.
  557. *
  558. * @throws TransformerException
  559. */
  560. public ElemTemplate getTemplate(XPathContext xctxt,
  561. int targetNode,
  562. QName mode,
  563. boolean quietConflictWarnings,
  564. DTM dtm)
  565. throws TransformerException
  566. {
  567. TemplateSubPatternAssociation head = getHead(xctxt, targetNode, dtm);
  568. if (null != head)
  569. {
  570. // XSLT functions, such as xsl:key, need to be able to get to
  571. // current ElemTemplateElement via a cast to the prefix resolver.
  572. // Setting this fixes bug idkey03.
  573. xctxt.pushNamespaceContextNull();
  574. xctxt.pushCurrentNodeAndExpression(targetNode, targetNode);
  575. try
  576. {
  577. do
  578. {
  579. ElemTemplate template = head.getTemplate();
  580. xctxt.setNamespaceContext(template);
  581. if ((head.m_stepPattern.execute(xctxt, targetNode) != NodeTest.SCORE_NONE)
  582. && head.matchMode(mode))
  583. {
  584. if (quietConflictWarnings)
  585. checkConflicts(head, xctxt, targetNode, mode);
  586. return template;
  587. }
  588. }
  589. while (null != (head = head.getNext()));
  590. }
  591. finally
  592. {
  593. xctxt.popCurrentNodeAndExpression();
  594. xctxt.popNamespaceContext();
  595. }
  596. }
  597. return null;
  598. } // end findTemplate
  599. /**
  600. * Given a target element, find the template that best
  601. * matches in the given XSL document, according
  602. * to the rules specified in the xsl draft.
  603. *
  604. * @param xctxt
  605. * @param targetNode
  606. * @param mode A string indicating the display mode.
  607. * @param maxImportLevel The maximum importCountComposed that we should consider or -1
  608. * if we should consider all import levels. This is used by apply-imports to
  609. * access templates that have been overridden.
  610. * @param maxEndImportLevel The count of composed imports
  611. * @param quietConflictWarnings
  612. * @return Rule that best matches targetElem.
  613. * @throws XSLProcessorException thrown if the active ProblemListener and XPathContext decide
  614. * the error condition is severe enough to halt processing.
  615. *
  616. * @throws TransformerException
  617. */
  618. public ElemTemplate getTemplate(XPathContext xctxt,
  619. int targetNode,
  620. QName mode,
  621. int maxImportLevel, int endImportLevel,
  622. boolean quietConflictWarnings,
  623. DTM dtm)
  624. throws TransformerException
  625. {
  626. TemplateSubPatternAssociation head = getHead(xctxt, targetNode, dtm);
  627. if (null != head)
  628. {
  629. // XSLT functions, such as xsl:key, need to be able to get to
  630. // current ElemTemplateElement via a cast to the prefix resolver.
  631. // Setting this fixes bug idkey03.
  632. xctxt.pushNamespaceContextNull();
  633. xctxt.pushCurrentNodeAndExpression(targetNode, targetNode);
  634. try
  635. {
  636. do
  637. {
  638. if ( (maxImportLevel > -1) && (head.getImportLevel() > maxImportLevel))
  639. {
  640. continue;
  641. }
  642. if (head.getImportLevel()<= maxImportLevel - endImportLevel)
  643. return null;
  644. ElemTemplate template = head.getTemplate();
  645. xctxt.setNamespaceContext(template);
  646. if ((head.m_stepPattern.execute(xctxt, targetNode) != NodeTest.SCORE_NONE)
  647. && head.matchMode(mode))
  648. {
  649. if (quietConflictWarnings)
  650. checkConflicts(head, xctxt, targetNode, mode);
  651. return template;
  652. }
  653. }
  654. while (null != (head = head.getNext()));
  655. }
  656. finally
  657. {
  658. xctxt.popCurrentNodeAndExpression();
  659. xctxt.popNamespaceContext();
  660. }
  661. }
  662. return null;
  663. } // end findTemplate
  664. /**
  665. * Get a TemplateWalker for use by a compiler. See the documentation for
  666. * the TreeWalker inner class for further details.
  667. */
  668. public TemplateWalker getWalker()
  669. {
  670. return new TemplateWalker();
  671. }
  672. /**
  673. * Check for match conflicts, and warn the stylesheet author.
  674. *
  675. * @param head Template pattern
  676. * @param xctxt Current XPath context
  677. * @param targetNode Node matching the pattern
  678. * @param mode reference, which may be null, to the <a href="http://www.w3.org/TR/xslt#modes">current mode</a>.
  679. */
  680. private void checkConflicts(TemplateSubPatternAssociation head,
  681. XPathContext xctxt, int targetNode, QName mode)
  682. {
  683. // TODO: Check for conflicts.
  684. }
  685. /**
  686. * Add object to vector if not already there.
  687. *
  688. * @param obj
  689. * @param v
  690. */
  691. private void addObjectIfNotFound(Object obj, Vector v)
  692. {
  693. int n = v.size();
  694. boolean addIt = true;
  695. for (int i = 0; i < n; i++)
  696. {
  697. if (v.elementAt(i) == obj)
  698. {
  699. addIt = false;
  700. break;
  701. }
  702. }
  703. if (addIt)
  704. {
  705. v.addElement(obj);
  706. }
  707. }
  708. /**
  709. * Keyed on string macro names, and holding values
  710. * that are macro elements in the XSL DOM tree.
  711. * Initialized in initMacroLookupTable, and used in
  712. * findNamedTemplate.
  713. * @serial
  714. */
  715. private Hashtable m_namedTemplates = new Hashtable(89);
  716. /**
  717. * This table is keyed on the target elements
  718. * of patterns, and contains linked lists of
  719. * the actual patterns that match the target element
  720. * to some degree of specifity.
  721. * @serial
  722. */
  723. private Hashtable m_patternTable = new Hashtable(89);
  724. /** Wildcard patterns.
  725. * @serial */
  726. private TemplateSubPatternAssociation m_wildCardPatterns = null;
  727. /** Text Patterns.
  728. * @serial */
  729. private TemplateSubPatternAssociation m_textPatterns = null;
  730. /** Root document Patterns.
  731. * @serial */
  732. private TemplateSubPatternAssociation m_docPatterns = null;
  733. /** Comment Patterns.
  734. * @serial */
  735. private TemplateSubPatternAssociation m_commentPatterns = null;
  736. /**
  737. * Get table of named Templates.
  738. * These are keyed on template names, and holding values
  739. * that are template elements.
  740. *
  741. * @return A Hashtable dictionary that contains {@link java.lang.String}s
  742. * as the keys, and {@link org.apache.xalan.templates.ElemTemplate}s as the
  743. * values.
  744. */
  745. private Hashtable getNamedTemplates()
  746. {
  747. return m_namedTemplates;
  748. }
  749. /**
  750. * Set table of named Templates.
  751. * These are keyed on string macro names, and holding values
  752. * that are template elements in the XSL DOM tree.
  753. *
  754. * @param v Hashtable dictionary that contains {@link java.lang.String}s
  755. * as the keys, and {@link org.apache.xalan.templates.ElemTemplate}s as the
  756. * values.
  757. */
  758. private void setNamedTemplates(Hashtable v)
  759. {
  760. m_namedTemplates = v;
  761. }
  762. /**
  763. * Get the head of the assocation list that is keyed by target.
  764. *
  765. * @param key The name of a node.
  766. *
  767. * @return The head of a linked list that contains all possible match pattern to
  768. * template associations for the given key.
  769. */
  770. private TemplateSubPatternAssociation getHead(String key)
  771. {
  772. return (TemplateSubPatternAssociation) m_patternTable.get(key);
  773. }
  774. /**
  775. * Get the head of the assocation list that is keyed by target.
  776. *
  777. * @param key
  778. * @param assoc
  779. */
  780. private void putHead(String key, TemplateSubPatternAssociation assoc)
  781. {
  782. if (key.equals(PsuedoNames.PSEUDONAME_TEXT))
  783. m_textPatterns = assoc;
  784. else if (key.equals(PsuedoNames.PSEUDONAME_ROOT))
  785. m_docPatterns = assoc;
  786. else if (key.equals(PsuedoNames.PSEUDONAME_COMMENT))
  787. m_commentPatterns = assoc;
  788. m_patternTable.put(key, assoc);
  789. }
  790. /**
  791. * An inner class used by a compiler to iterate over all of the ElemTemplates
  792. * stored in this TemplateList. The compiler can replace returned templates
  793. * with their compiled equivalent.
  794. */
  795. public class TemplateWalker
  796. {
  797. private Enumeration hashIterator;
  798. private boolean inPatterns;
  799. private TemplateSubPatternAssociation curPattern;
  800. private Hashtable m_compilerCache = new Hashtable();
  801. private TemplateWalker()
  802. {
  803. hashIterator = m_patternTable.elements();
  804. inPatterns = true;
  805. curPattern = null;
  806. }
  807. public ElemTemplate next()
  808. {
  809. ElemTemplate retValue = null;
  810. ElemTemplate ct;
  811. while (true)
  812. {
  813. if (inPatterns)
  814. {
  815. if (null != curPattern)
  816. curPattern = curPattern.getNext();
  817. if (null != curPattern)
  818. retValue = curPattern.getTemplate();
  819. else
  820. {
  821. if (hashIterator.hasMoreElements())
  822. {
  823. curPattern = (TemplateSubPatternAssociation) hashIterator.nextElement();
  824. retValue = curPattern.getTemplate();
  825. }
  826. else
  827. {
  828. inPatterns = false;
  829. hashIterator = m_namedTemplates.elements();
  830. }
  831. }
  832. }
  833. if (!inPatterns)
  834. {
  835. if (hashIterator.hasMoreElements())
  836. retValue = (ElemTemplate) hashIterator.nextElement();
  837. else
  838. return null;
  839. }
  840. ct = (ElemTemplate) m_compilerCache.get(new Integer(retValue.getUid()));
  841. if (null == ct)
  842. {
  843. m_compilerCache.put(new Integer(retValue.getUid()), retValue);
  844. return retValue;
  845. }
  846. }
  847. }
  848. }
  849. }