001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 /* 019 * $Id: TemplateList.java 468643 2006-10-28 06:56:03Z minchau $ 020 */ 021 package org.apache.xalan.templates; 022 023 import java.util.Enumeration; 024 import java.util.Hashtable; 025 import java.util.Vector; 026 027 import javax.xml.transform.TransformerException; 028 029 import org.apache.xalan.res.XSLTErrorResources; 030 import org.apache.xml.dtm.DTM; 031 import org.apache.xml.utils.QName; 032 import org.apache.xpath.Expression; 033 import org.apache.xpath.XPath; 034 import org.apache.xpath.XPathContext; 035 import org.apache.xpath.compiler.PsuedoNames; 036 import org.apache.xpath.patterns.NodeTest; 037 import org.apache.xpath.patterns.StepPattern; 038 import org.apache.xpath.patterns.UnionPattern; 039 040 /** 041 * Encapsulates a template list, and helps locate individual templates. 042 * @xsl.usage advanced 043 */ 044 public class TemplateList implements java.io.Serializable 045 { 046 static final long serialVersionUID = 5803675288911728791L; 047 048 /** 049 * Construct a TemplateList object. Needs to be public so it can 050 * be invoked from the CompilingStylesheetHandler. 051 */ 052 public TemplateList() 053 { 054 super(); 055 } 056 057 /** 058 * Add a template to the table of named templates and/or the table of templates 059 * with match patterns. This routine should 060 * be called in decreasing order of precedence but it checks nonetheless. 061 * 062 * @param template 063 */ 064 public void setTemplate(ElemTemplate template) 065 { 066 XPath matchXPath = template.getMatch(); 067 068 if (null == template.getName() && null == matchXPath) 069 { 070 template.error(XSLTErrorResources.ER_NEED_NAME_OR_MATCH_ATTRIB, 071 new Object[]{ "xsl:template" }); 072 } 073 074 if (null != template.getName()) 075 { 076 ElemTemplate existingTemplate = (ElemTemplate) m_namedTemplates.get(template.getName()); 077 if (null == existingTemplate) 078 { 079 m_namedTemplates.put(template.getName(), template); 080 } 081 else 082 { 083 int existingPrecedence = 084 existingTemplate.getStylesheetComposed().getImportCountComposed(); 085 int newPrecedence = template.getStylesheetComposed().getImportCountComposed(); 086 if (newPrecedence > existingPrecedence) 087 { 088 // This should never happen 089 m_namedTemplates.put(template.getName(), template); 090 } 091 else if (newPrecedence == existingPrecedence) 092 template.error(XSLTErrorResources.ER_DUPLICATE_NAMED_TEMPLATE, 093 new Object[]{ template.getName() }); 094 } 095 } 096 097 098 099 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 */ 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 868 private TemplateWalker() 869 { 870 hashIterator = m_patternTable.elements(); 871 inPatterns = true; 872 curPattern = null; 873 } 874 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 }