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