1. /*
  2. * Copyright 2001-2004 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /*
  17. * $Id: Stylesheet.java,v 1.59 2004/02/16 22:24:29 minchau Exp $
  18. */
  19. package com.sun.org.apache.xalan.internal.xsltc.compiler;
  20. import java.net.URL;
  21. import java.net.MalformedURLException;
  22. import java.util.Vector;
  23. import java.util.Enumeration;
  24. import java.util.Hashtable;
  25. import java.util.Iterator;
  26. import java.util.Properties;
  27. import java.util.StringTokenizer;
  28. import com.sun.org.apache.xml.internal.utils.SystemIDResolver;
  29. import com.sun.org.apache.bcel.internal.generic.ANEWARRAY;
  30. import com.sun.org.apache.bcel.internal.generic.BasicType;
  31. import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
  32. import com.sun.org.apache.bcel.internal.generic.FieldGen;
  33. import com.sun.org.apache.bcel.internal.generic.GETFIELD;
  34. import com.sun.org.apache.bcel.internal.generic.GETSTATIC;
  35. import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
  36. import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
  37. import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
  38. import com.sun.org.apache.bcel.internal.generic.ISTORE;
  39. import com.sun.org.apache.bcel.internal.generic.InstructionHandle;
  40. import com.sun.org.apache.bcel.internal.generic.InstructionList;
  41. import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
  42. import com.sun.org.apache.bcel.internal.generic.NEW;
  43. import com.sun.org.apache.bcel.internal.generic.NEWARRAY;
  44. import com.sun.org.apache.bcel.internal.generic.PUSH;
  45. import com.sun.org.apache.bcel.internal.generic.PUTFIELD;
  46. import com.sun.org.apache.bcel.internal.generic.PUTSTATIC;
  47. import com.sun.org.apache.bcel.internal.generic.TargetLostException;
  48. import com.sun.org.apache.bcel.internal.util.InstructionFinder;
  49. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
  50. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
  51. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
  52. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
  53. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
  54. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
  55. import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
  56. import com.sun.org.apache.xml.internal.dtm.DTM;
  57. /**
  58. * @author Jacek Ambroziak
  59. * @author Santiago Pericas-Geertsen
  60. * @author Morten Jorgensen
  61. */
  62. public final class Stylesheet extends SyntaxTreeNode {
  63. /**
  64. * XSLT version defined in the stylesheet.
  65. */
  66. private String _version;
  67. /**
  68. * Internal name of this stylesheet used as a key into the symbol table.
  69. */
  70. private QName _name;
  71. /**
  72. * A URI that represents the system ID for this stylesheet.
  73. */
  74. private String _systemId;
  75. /**
  76. * A reference to the parent stylesheet or null if topmost.
  77. */
  78. private Stylesheet _parentStylesheet;
  79. /**
  80. * Contains global variables and parameters defined in the stylesheet.
  81. */
  82. private Vector _globals = new Vector();
  83. /**
  84. * Used to cache the result returned by <code>hasLocalParams()</code>.
  85. */
  86. private Boolean _hasLocalParams = null;
  87. /**
  88. * The name of the class being generated.
  89. */
  90. private String _className;
  91. /**
  92. * Contains all templates defined in this stylesheet
  93. */
  94. private final Vector _templates = new Vector();
  95. /**
  96. * Used to cache result of <code>getAllValidTemplates()</code>. Only
  97. * set in top-level stylesheets that include/import other stylesheets.
  98. */
  99. private Vector _allValidTemplates = null;
  100. /**
  101. * Counter to generate unique mode suffixes.
  102. */
  103. private int _nextModeSerial = 1;
  104. /**
  105. * Mapping between mode names and Mode instances.
  106. */
  107. private final Hashtable _modes = new Hashtable();
  108. /**
  109. * A reference to the default Mode object.
  110. */
  111. private Mode _defaultMode;
  112. /**
  113. * Mapping between extension URIs and their prefixes.
  114. */
  115. private final Hashtable _extensions = new Hashtable();
  116. /**
  117. * Reference to the stylesheet from which this stylesheet was
  118. * imported (if any).
  119. */
  120. public Stylesheet _importedFrom = null;
  121. /**
  122. * Reference to the stylesheet from which this stylesheet was
  123. * included (if any).
  124. */
  125. public Stylesheet _includedFrom = null;
  126. /**
  127. * Array of all the stylesheets imported or included from this one.
  128. */
  129. private Vector _includedStylesheets = null;
  130. /**
  131. * Import precendence for this stylesheet.
  132. */
  133. private int _importPrecedence = 1;
  134. /**
  135. * Minimum precendence of any descendant stylesheet by inclusion or
  136. * importation.
  137. */
  138. private int _minimumDescendantPrecedence = -1;
  139. /**
  140. * Mapping between key names and Key objects (needed by Key/IdPattern).
  141. */
  142. private Hashtable _keys = new Hashtable();
  143. /**
  144. * A reference to the SourceLoader set by the user (a URIResolver
  145. * if the JAXP API is being used).
  146. */
  147. private SourceLoader _loader = null;
  148. /**
  149. * Flag indicating if format-number() is called.
  150. */
  151. private boolean _numberFormattingUsed = false;
  152. /**
  153. * Flag indicating if this is a simplified stylesheets. A template
  154. * matching on "/" must be added in this case.
  155. */
  156. private boolean _simplified = false;
  157. /**
  158. * Flag indicating if multi-document support is needed.
  159. */
  160. private boolean _multiDocument = false;
  161. /**
  162. * Flag indicating if nodset() is called.
  163. */
  164. private boolean _callsNodeset = false;
  165. /**
  166. * Flag indicating if id() is called.
  167. */
  168. private boolean _hasIdCall = false;
  169. /**
  170. * Set to true to enable template inlining optimization.
  171. */
  172. private boolean _templateInlining = true;
  173. /**
  174. * A reference to the last xsl:output object found in the styleshet.
  175. */
  176. private Output _lastOutputElement = null;
  177. /**
  178. * Output properties for this stylesheet.
  179. */
  180. private Properties _outputProperties = null;
  181. /**
  182. * Output method for this stylesheet (must be set to one of
  183. * the constants defined below).
  184. */
  185. private int _outputMethod = UNKNOWN_OUTPUT;
  186. // Output method constants
  187. public static final int UNKNOWN_OUTPUT = 0;
  188. public static final int XML_OUTPUT = 1;
  189. public static final int HTML_OUTPUT = 2;
  190. public static final int TEXT_OUTPUT = 3;
  191. /**
  192. * Return the output method
  193. */
  194. public int getOutputMethod() {
  195. return _outputMethod;
  196. }
  197. /**
  198. * Check and set the output method
  199. */
  200. private void checkOutputMethod() {
  201. if (_lastOutputElement != null) {
  202. String method = _lastOutputElement.getOutputMethod();
  203. if (method != null) {
  204. if (method.equals("xml"))
  205. _outputMethod = XML_OUTPUT;
  206. else if (method.equals("html"))
  207. _outputMethod = HTML_OUTPUT;
  208. else if (method.equals("text"))
  209. _outputMethod = TEXT_OUTPUT;
  210. }
  211. }
  212. }
  213. public boolean getTemplateInlining() {
  214. return _templateInlining;
  215. }
  216. public void setTemplateInlining(boolean flag) {
  217. _templateInlining = flag;
  218. }
  219. public boolean isSimplified() {
  220. return(_simplified);
  221. }
  222. public void setSimplified() {
  223. _simplified = true;
  224. }
  225. public void setHasIdCall(boolean flag) {
  226. _hasIdCall = flag;
  227. }
  228. public void setOutputProperty(String key, String value) {
  229. if (_outputProperties == null) {
  230. _outputProperties = new Properties();
  231. }
  232. _outputProperties.setProperty(key, value);
  233. }
  234. public void setOutputProperties(Properties props) {
  235. _outputProperties = props;
  236. }
  237. public Properties getOutputProperties() {
  238. return _outputProperties;
  239. }
  240. public Output getLastOutputElement() {
  241. return _lastOutputElement;
  242. }
  243. public void setMultiDocument(boolean flag) {
  244. _multiDocument = flag;
  245. }
  246. public boolean isMultiDocument() {
  247. return _multiDocument;
  248. }
  249. public void setCallsNodeset(boolean flag) {
  250. if (flag) setMultiDocument(flag);
  251. _callsNodeset = flag;
  252. }
  253. public boolean callsNodeset() {
  254. return _callsNodeset;
  255. }
  256. public void numberFormattingUsed() {
  257. _numberFormattingUsed = true;
  258. /*
  259. * Fix for bug 23046, if the stylesheet is included, set the
  260. * numberFormattingUsed flag to the parent stylesheet too.
  261. * AbstractTranslet.addDecimalFormat() will be inlined once for the
  262. * outer most stylesheet.
  263. */
  264. Stylesheet parent = getParentStylesheet();
  265. if (null != parent) parent.numberFormattingUsed();
  266. }
  267. public void setImportPrecedence(final int precedence) {
  268. // Set import precedence for this stylesheet
  269. _importPrecedence = precedence;
  270. // Set import precedence for all included stylesheets
  271. final Enumeration elements = elements();
  272. while (elements.hasMoreElements()) {
  273. SyntaxTreeNode child = (SyntaxTreeNode)elements.nextElement();
  274. if (child instanceof Include) {
  275. Stylesheet included = ((Include)child).getIncludedStylesheet();
  276. if (included != null && included._includedFrom == this) {
  277. included.setImportPrecedence(precedence);
  278. }
  279. }
  280. }
  281. // Set import precedence for the stylesheet that imported this one
  282. if (_importedFrom != null) {
  283. if (_importedFrom.getImportPrecedence() < precedence) {
  284. final Parser parser = getParser();
  285. final int nextPrecedence = parser.getNextImportPrecedence();
  286. _importedFrom.setImportPrecedence(nextPrecedence);
  287. }
  288. }
  289. // Set import precedence for the stylesheet that included this one
  290. else if (_includedFrom != null) {
  291. if (_includedFrom.getImportPrecedence() != precedence)
  292. _includedFrom.setImportPrecedence(precedence);
  293. }
  294. }
  295. public int getImportPrecedence() {
  296. return _importPrecedence;
  297. }
  298. /**
  299. * Get the minimum of the precedence of this stylesheet, any stylesheet
  300. * imported by this stylesheet and any include/import descendant of this
  301. * stylesheet.
  302. */
  303. public int getMinimumDescendantPrecedence() {
  304. if (_minimumDescendantPrecedence == -1) {
  305. // Start with precedence of current stylesheet as a basis.
  306. int min = getImportPrecedence();
  307. // Recursively examine all imported/included stylesheets.
  308. final int inclImpCount = (_includedStylesheets != null)
  309. ? _includedStylesheets.size()
  310. : 0;
  311. for (int i = 0; i < inclImpCount; i++) {
  312. int prec = ((Stylesheet)_includedStylesheets.elementAt(i))
  313. .getMinimumDescendantPrecedence();
  314. if (prec < min) {
  315. min = prec;
  316. }
  317. }
  318. _minimumDescendantPrecedence = min;
  319. }
  320. return _minimumDescendantPrecedence;
  321. }
  322. public boolean checkForLoop(String systemId) {
  323. // Return true if this stylesheet includes/imports itself
  324. if (_systemId != null && _systemId.equals(systemId)) {
  325. return true;
  326. }
  327. // Then check with any stylesheets that included/imported this one
  328. if (_parentStylesheet != null)
  329. return _parentStylesheet.checkForLoop(systemId);
  330. // Otherwise OK
  331. return false;
  332. }
  333. public void setParser(Parser parser) {
  334. super.setParser(parser);
  335. _name = makeStylesheetName("__stylesheet_");
  336. }
  337. public void setParentStylesheet(Stylesheet parent) {
  338. _parentStylesheet = parent;
  339. }
  340. public Stylesheet getParentStylesheet() {
  341. return _parentStylesheet;
  342. }
  343. public void setImportingStylesheet(Stylesheet parent) {
  344. _importedFrom = parent;
  345. parent.addIncludedStylesheet(this);
  346. }
  347. public void setIncludingStylesheet(Stylesheet parent) {
  348. _includedFrom = parent;
  349. parent.addIncludedStylesheet(this);
  350. }
  351. public void addIncludedStylesheet(Stylesheet child) {
  352. if (_includedStylesheets == null) {
  353. _includedStylesheets = new Vector();
  354. }
  355. _includedStylesheets.addElement(child);
  356. }
  357. public void setSystemId(String systemId) {
  358. if (systemId != null) {
  359. _systemId = SystemIDResolver.getAbsoluteURI(systemId);
  360. }
  361. }
  362. public String getSystemId() {
  363. return _systemId;
  364. }
  365. public void setSourceLoader(SourceLoader loader) {
  366. _loader = loader;
  367. }
  368. public SourceLoader getSourceLoader() {
  369. return _loader;
  370. }
  371. private QName makeStylesheetName(String prefix) {
  372. return getParser().getQName(prefix+getXSLTC().nextStylesheetSerial());
  373. }
  374. /**
  375. * Returns true if this stylesheet has global vars or params.
  376. */
  377. public boolean hasGlobals() {
  378. return _globals.size() > 0;
  379. }
  380. /**
  381. * Returns true if at least one template in the stylesheet has params
  382. * defined. Uses the variable <code>_hasLocalParams</code> to cache the
  383. * result.
  384. */
  385. public boolean hasLocalParams() {
  386. if (_hasLocalParams == null) {
  387. Vector templates = getAllValidTemplates();
  388. final int n = templates.size();
  389. for (int i = 0; i < n; i++) {
  390. final Template template = (Template)templates.elementAt(i);
  391. if (template.hasParams()) {
  392. _hasLocalParams = new Boolean(true);
  393. return true;
  394. }
  395. }
  396. _hasLocalParams = new Boolean(false);
  397. return false;
  398. }
  399. else {
  400. return _hasLocalParams.booleanValue();
  401. }
  402. }
  403. /**
  404. * Adds a single prefix mapping to this syntax tree node.
  405. * @param prefix Namespace prefix.
  406. * @param uri Namespace URI.
  407. */
  408. protected void addPrefixMapping(String prefix, String uri) {
  409. if (prefix.equals(EMPTYSTRING) && uri.equals(XHTML_URI)) return;
  410. super.addPrefixMapping(prefix, uri);
  411. }
  412. /**
  413. * Store extension URIs
  414. */
  415. private void extensionURI(String prefixes, SymbolTable stable) {
  416. if (prefixes != null) {
  417. StringTokenizer tokens = new StringTokenizer(prefixes);
  418. while (tokens.hasMoreTokens()) {
  419. final String prefix = tokens.nextToken();
  420. final String uri = lookupNamespace(prefix);
  421. if (uri != null) {
  422. _extensions.put(uri, prefix);
  423. }
  424. }
  425. }
  426. }
  427. public boolean isExtension(String uri) {
  428. return (_extensions.get(uri) != null);
  429. }
  430. public void excludeExtensionPrefixes(Parser parser) {
  431. final SymbolTable stable = parser.getSymbolTable();
  432. final String excludePrefixes = getAttribute("exclude-result-prefixes");
  433. final String extensionPrefixes = getAttribute("extension-element-prefixes");
  434. // Exclude XSLT uri
  435. stable.excludeURI(Constants.XSLT_URI);
  436. stable.excludeNamespaces(excludePrefixes);
  437. stable.excludeNamespaces(extensionPrefixes);
  438. extensionURI(extensionPrefixes, stable);
  439. }
  440. /**
  441. * Parse the version and uri fields of the stylesheet and add an
  442. * entry to the symbol table mapping the name <tt>__stylesheet_</tt>
  443. * to an instance of this class.
  444. */
  445. public void parseContents(Parser parser) {
  446. final SymbolTable stable = parser.getSymbolTable();
  447. /*
  448. // Make sure the XSL version set in this stylesheet
  449. if ((_version == null) || (_version.equals(EMPTYSTRING))) {
  450. reportError(this, parser, ErrorMsg.REQUIRED_ATTR_ERR,"version");
  451. }
  452. // Verify that the version is 1.0 and nothing else
  453. else if (!_version.equals("1.0")) {
  454. reportError(this, parser, ErrorMsg.XSL_VERSION_ERR, _version);
  455. }
  456. */
  457. // Add the implicit mapping of 'xml' to the XML namespace URI
  458. addPrefixMapping("xml", "http://www.w3.org/XML/1998/namespace");
  459. // Report and error if more than one stylesheet defined
  460. final Stylesheet sheet = stable.addStylesheet(_name, this);
  461. if (sheet != null) {
  462. // Error: more that one stylesheet defined
  463. ErrorMsg err = new ErrorMsg(ErrorMsg.MULTIPLE_STYLESHEET_ERR,this);
  464. parser.reportError(Constants.ERROR, err);
  465. }
  466. // If this is a simplified stylesheet we must create a template that
  467. // grabs the root node of the input doc ( <xsl:template match="/"/> ).
  468. // This template needs the current element (the one passed to this
  469. // method) as its only child, so the Template class has a special
  470. // method that handles this (parseSimplified()).
  471. if (_simplified) {
  472. stable.excludeURI(XSLT_URI);
  473. Template template = new Template();
  474. template.parseSimplified(this, parser);
  475. }
  476. // Parse the children of this node
  477. else {
  478. parseOwnChildren(parser);
  479. }
  480. }
  481. /**
  482. * Parse all direct children of the <xsl:stylesheet/> element.
  483. */
  484. public final void parseOwnChildren(Parser parser) {
  485. final Vector contents = getContents();
  486. final int count = contents.size();
  487. // We have to scan the stylesheet element's top-level elements for
  488. // variables and/or parameters before we parse the other elements
  489. for (int i = 0; i < count; i++) {
  490. SyntaxTreeNode child = (SyntaxTreeNode)contents.elementAt(i);
  491. if ((child instanceof VariableBase) ||
  492. (child instanceof NamespaceAlias)) {
  493. parser.getSymbolTable().setCurrentNode(child);
  494. child.parseContents(parser);
  495. }
  496. }
  497. // Now go through all the other top-level elements...
  498. for (int i = 0; i < count; i++) {
  499. SyntaxTreeNode child = (SyntaxTreeNode)contents.elementAt(i);
  500. if (!(child instanceof VariableBase) &&
  501. !(child instanceof NamespaceAlias)) {
  502. parser.getSymbolTable().setCurrentNode(child);
  503. child.parseContents(parser);
  504. }
  505. // All template code should be compiled as methods if the
  506. // <xsl:apply-imports/> element was ever used in this stylesheet
  507. if (!_templateInlining && (child instanceof Template)) {
  508. Template template = (Template)child;
  509. String name = "template$dot$" + template.getPosition();
  510. template.setName(parser.getQName(name));
  511. }
  512. }
  513. }
  514. public void processModes() {
  515. if (_defaultMode == null)
  516. _defaultMode = new Mode(null, this, Constants.EMPTYSTRING);
  517. _defaultMode.processPatterns(_keys);
  518. final Enumeration modes = _modes.elements();
  519. while (modes.hasMoreElements()) {
  520. final Mode mode = (Mode)modes.nextElement();
  521. mode.processPatterns(_keys);
  522. }
  523. }
  524. private void compileModes(ClassGenerator classGen) {
  525. _defaultMode.compileApplyTemplates(classGen);
  526. final Enumeration modes = _modes.elements();
  527. while (modes.hasMoreElements()) {
  528. final Mode mode = (Mode)modes.nextElement();
  529. mode.compileApplyTemplates(classGen);
  530. }
  531. }
  532. public Mode getMode(QName modeName) {
  533. if (modeName == null) {
  534. if (_defaultMode == null) {
  535. _defaultMode = new Mode(null, this, Constants.EMPTYSTRING);
  536. }
  537. return _defaultMode;
  538. }
  539. else {
  540. Mode mode = (Mode)_modes.get(modeName);
  541. if (mode == null) {
  542. final String suffix = Integer.toString(_nextModeSerial++);
  543. _modes.put(modeName, mode = new Mode(modeName, this, suffix));
  544. }
  545. return mode;
  546. }
  547. }
  548. /**
  549. * Type check all the children of this node.
  550. */
  551. public Type typeCheck(SymbolTable stable) throws TypeCheckError {
  552. final int count = _globals.size();
  553. for (int i = 0; i < count; i++) {
  554. final VariableBase var = (VariableBase)_globals.elementAt(i);
  555. var.typeCheck(stable);
  556. }
  557. return typeCheckContents(stable);
  558. }
  559. /**
  560. * Translate the stylesheet into JVM bytecodes.
  561. */
  562. public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
  563. translate();
  564. }
  565. private void addDOMField(ClassGenerator classGen) {
  566. final FieldGen fgen = new FieldGen(ACC_PUBLIC,
  567. Util.getJCRefType(DOM_INTF_SIG),
  568. DOM_FIELD,
  569. classGen.getConstantPool());
  570. classGen.addField(fgen.getField());
  571. }
  572. /**
  573. * Add a static field
  574. */
  575. private void addStaticField(ClassGenerator classGen, String type,
  576. String name)
  577. {
  578. final FieldGen fgen = new FieldGen(ACC_PROTECTED|ACC_STATIC,
  579. Util.getJCRefType(type),
  580. name,
  581. classGen.getConstantPool());
  582. classGen.addField(fgen.getField());
  583. }
  584. /**
  585. * Translate the stylesheet into JVM bytecodes.
  586. */
  587. public void translate() {
  588. _className = getXSLTC().getClassName();
  589. // Define a new class by extending TRANSLET_CLASS
  590. final ClassGenerator classGen =
  591. new ClassGenerator(_className,
  592. TRANSLET_CLASS,
  593. Constants.EMPTYSTRING,
  594. ACC_PUBLIC | ACC_SUPER,
  595. null, this);
  596. addDOMField(classGen);
  597. // Compile transform() to initialize parameters, globals & output
  598. // and run the transformation
  599. compileTransform(classGen);
  600. // Translate all non-template elements and filter out all templates
  601. final Enumeration elements = elements();
  602. while (elements.hasMoreElements()) {
  603. Object element = elements.nextElement();
  604. // xsl:template
  605. if (element instanceof Template) {
  606. // Separate templates by modes
  607. final Template template = (Template)element;
  608. //_templates.addElement(template);
  609. getMode(template.getModeName()).addTemplate(template);
  610. }
  611. // xsl:attribute-set
  612. else if (element instanceof AttributeSet) {
  613. ((AttributeSet)element).translate(classGen, null);
  614. }
  615. else if (element instanceof Output) {
  616. // save the element for later to pass to compileConstructor
  617. Output output = (Output)element;
  618. if (output.enabled()) _lastOutputElement = output;
  619. }
  620. else {
  621. // Global variables and parameters are handled elsewhere.
  622. // Other top-level non-template elements are ignored. Literal
  623. // elements outside of templates will never be output.
  624. }
  625. }
  626. checkOutputMethod();
  627. processModes();
  628. compileModes(classGen);
  629. compileStaticInitializer(classGen);
  630. compileConstructor(classGen, _lastOutputElement);
  631. if (!getParser().errorsFound()) {
  632. getXSLTC().dumpClass(classGen.getJavaClass());
  633. }
  634. }
  635. /**
  636. * Compile the namesArray, urisArray and typesArray into
  637. * the static initializer. They are read-only from the
  638. * translet. All translet instances can share a single
  639. * copy of this informtion.
  640. */
  641. private void compileStaticInitializer(ClassGenerator classGen) {
  642. final ConstantPoolGen cpg = classGen.getConstantPool();
  643. final InstructionList il = new InstructionList();
  644. final MethodGenerator staticConst =
  645. new MethodGenerator(ACC_PUBLIC|ACC_STATIC,
  646. com.sun.org.apache.bcel.internal.generic.Type.VOID,
  647. null, null, "<clinit>",
  648. _className, il, cpg);
  649. addStaticField(classGen, "[" + STRING_SIG, STATIC_NAMES_ARRAY_FIELD);
  650. addStaticField(classGen, "[" + STRING_SIG, STATIC_URIS_ARRAY_FIELD);
  651. addStaticField(classGen, "[I", STATIC_TYPES_ARRAY_FIELD);
  652. addStaticField(classGen, "[" + STRING_SIG, STATIC_NAMESPACE_ARRAY_FIELD);
  653. // Create fields of type char[] that will contain literal text from
  654. // the stylesheet.
  655. final int charDataFieldCount = getXSLTC().getCharacterDataCount();
  656. for (int i = 0; i < charDataFieldCount; i++) {
  657. addStaticField(classGen, STATIC_CHAR_DATA_FIELD_SIG,
  658. STATIC_CHAR_DATA_FIELD+i);
  659. }
  660. // Put the names array into the translet - used for dom/translet mapping
  661. final Vector namesIndex = getXSLTC().getNamesIndex();
  662. int size = namesIndex.size();
  663. String[] namesArray = new String[size];
  664. String[] urisArray = new String[size];
  665. int[] typesArray = new int[size];
  666. int index;
  667. for (int i = 0; i < size; i++) {
  668. String encodedName = (String)namesIndex.elementAt(i);
  669. if ((index = encodedName.lastIndexOf(':')) > -1) {
  670. urisArray[i] = encodedName.substring(0, index);
  671. }
  672. index = index + 1;
  673. if (encodedName.charAt(index) == '@') {
  674. typesArray[i] = DTM.ATTRIBUTE_NODE;
  675. index++;
  676. } else if (encodedName.charAt(index) == '?') {
  677. typesArray[i] = DTM.NAMESPACE_NODE;
  678. index++;
  679. } else {
  680. typesArray[i] = DTM.ELEMENT_NODE;
  681. }
  682. if (index == 0) {
  683. namesArray[i] = encodedName;
  684. }
  685. else {
  686. namesArray[i] = encodedName.substring(index);
  687. }
  688. }
  689. il.append(new PUSH(cpg, size));
  690. il.append(new ANEWARRAY(cpg.addClass(STRING)));
  691. for (int i = 0; i < size; i++) {
  692. final String name = namesArray[i];
  693. il.append(DUP);
  694. il.append(new PUSH(cpg, i));
  695. il.append(new PUSH(cpg, name));
  696. il.append(AASTORE);
  697. }
  698. il.append(new PUTSTATIC(cpg.addFieldref(_className,
  699. STATIC_NAMES_ARRAY_FIELD,
  700. NAMES_INDEX_SIG)));
  701. il.append(new PUSH(cpg, size));
  702. il.append(new ANEWARRAY(cpg.addClass(STRING)));
  703. for (int i = 0; i < size; i++) {
  704. final String uri = urisArray[i];
  705. il.append(DUP);
  706. il.append(new PUSH(cpg, i));
  707. il.append(new PUSH(cpg, uri));
  708. il.append(AASTORE);
  709. }
  710. il.append(new PUTSTATIC(cpg.addFieldref(_className,
  711. STATIC_URIS_ARRAY_FIELD,
  712. URIS_INDEX_SIG)));
  713. il.append(new PUSH(cpg, size));
  714. il.append(new NEWARRAY(BasicType.INT));
  715. for (int i = 0; i < size; i++) {
  716. final int nodeType = typesArray[i];
  717. il.append(DUP);
  718. il.append(new PUSH(cpg, i));
  719. il.append(new PUSH(cpg, nodeType));
  720. il.append(IASTORE);
  721. }
  722. il.append(new PUTSTATIC(cpg.addFieldref(_className,
  723. STATIC_TYPES_ARRAY_FIELD,
  724. TYPES_INDEX_SIG)));
  725. // Put the namespace names array into the translet
  726. final Vector namespaces = getXSLTC().getNamespaceIndex();
  727. il.append(new PUSH(cpg, namespaces.size()));
  728. il.append(new ANEWARRAY(cpg.addClass(STRING)));
  729. for (int i = 0; i < namespaces.size(); i++) {
  730. final String ns = (String)namespaces.elementAt(i);
  731. il.append(DUP);
  732. il.append(new PUSH(cpg, i));
  733. il.append(new PUSH(cpg, ns));
  734. il.append(AASTORE);
  735. }
  736. il.append(new PUTSTATIC(cpg.addFieldref(_className,
  737. STATIC_NAMESPACE_ARRAY_FIELD,
  738. NAMESPACE_INDEX_SIG)));
  739. // Grab all the literal text in the stylesheet and put it in a char[]
  740. final int charDataCount = getXSLTC().getCharacterDataCount();
  741. final int toCharArray = cpg.addMethodref(STRING, "toCharArray", "()[C");
  742. for (int i = 0; i < charDataCount; i++) {
  743. il.append(new PUSH(cpg, getXSLTC().getCharacterData(i)));
  744. il.append(new INVOKEVIRTUAL(toCharArray));
  745. il.append(new PUTSTATIC(cpg.addFieldref(_className,
  746. STATIC_CHAR_DATA_FIELD+i,
  747. STATIC_CHAR_DATA_FIELD_SIG)));
  748. }
  749. il.append(RETURN);
  750. staticConst.stripAttributes(true);
  751. staticConst.setMaxLocals();
  752. staticConst.setMaxStack();
  753. classGen.addMethod(staticConst.getMethod());
  754. }
  755. /**
  756. * Compile the translet's constructor
  757. */
  758. private void compileConstructor(ClassGenerator classGen, Output output) {
  759. final ConstantPoolGen cpg = classGen.getConstantPool();
  760. final InstructionList il = new InstructionList();
  761. final MethodGenerator constructor =
  762. new MethodGenerator(ACC_PUBLIC,
  763. com.sun.org.apache.bcel.internal.generic.Type.VOID,
  764. null, null, "<init>",
  765. _className, il, cpg);
  766. // Call the constructor in the AbstractTranslet superclass
  767. il.append(classGen.loadTranslet());
  768. il.append(new INVOKESPECIAL(cpg.addMethodref(TRANSLET_CLASS,
  769. "<init>", "()V")));
  770. il.append(classGen.loadTranslet());
  771. il.append(new GETSTATIC(cpg.addFieldref(_className,
  772. STATIC_NAMES_ARRAY_FIELD,
  773. NAMES_INDEX_SIG)));
  774. il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS,
  775. NAMES_INDEX,
  776. NAMES_INDEX_SIG)));
  777. il.append(classGen.loadTranslet());
  778. il.append(new GETSTATIC(cpg.addFieldref(_className,
  779. STATIC_URIS_ARRAY_FIELD,
  780. URIS_INDEX_SIG)));
  781. il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS,
  782. URIS_INDEX,
  783. URIS_INDEX_SIG)));
  784. il.append(classGen.loadTranslet());
  785. il.append(new GETSTATIC(cpg.addFieldref(_className,
  786. STATIC_TYPES_ARRAY_FIELD,
  787. TYPES_INDEX_SIG)));
  788. il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS,
  789. TYPES_INDEX,
  790. TYPES_INDEX_SIG)));
  791. il.append(classGen.loadTranslet());
  792. il.append(new GETSTATIC(cpg.addFieldref(_className,
  793. STATIC_NAMESPACE_ARRAY_FIELD,
  794. NAMESPACE_INDEX_SIG)));
  795. il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS,
  796. NAMESPACE_INDEX,
  797. NAMESPACE_INDEX_SIG)));
  798. il.append(classGen.loadTranslet());
  799. il.append(new PUSH(cpg, AbstractTranslet.CURRENT_TRANSLET_VERSION));
  800. il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS,
  801. TRANSLET_VERSION_INDEX,
  802. TRANSLET_VERSION_INDEX_SIG)));
  803. if (_hasIdCall) {
  804. il.append(classGen.loadTranslet());
  805. il.append(new PUSH(cpg, Boolean.TRUE));
  806. il.append(new PUTFIELD(cpg.addFieldref(TRANSLET_CLASS,
  807. HASIDCALL_INDEX,
  808. HASIDCALL_INDEX_SIG)));
  809. }
  810. // Compile in code to set the output configuration from <xsl:output>
  811. if (output != null) {
  812. // Set all the output settings files in the translet
  813. output.translate(classGen, constructor);
  814. }
  815. // Compile default decimal formatting symbols.
  816. // This is an implicit, nameless xsl:decimal-format top-level element.
  817. if (_numberFormattingUsed)
  818. DecimalFormatting.translateDefaultDFS(classGen, constructor);
  819. il.append(RETURN);
  820. constructor.stripAttributes(true);
  821. constructor.setMaxLocals();
  822. constructor.setMaxStack();
  823. classGen.addMethod(constructor.getMethod());
  824. }
  825. /**
  826. * Compile a topLevel() method into the output class. This method is
  827. * called from transform() to handle all non-template top-level elemtents.
  828. * Returns the signature of the topLevel() method.
  829. */
  830. private String compileTopLevel(ClassGenerator classGen,
  831. Enumeration elements) {
  832. final ConstantPoolGen cpg = classGen.getConstantPool();
  833. final com.sun.org.apache.bcel.internal.generic.Type[] argTypes = {
  834. Util.getJCRefType(DOM_INTF_SIG),
  835. Util.getJCRefType(NODE_ITERATOR_SIG),
  836. Util.getJCRefType(TRANSLET_OUTPUT_SIG)
  837. };
  838. final String[] argNames = {
  839. DOCUMENT_PNAME, ITERATOR_PNAME, TRANSLET_OUTPUT_PNAME
  840. };
  841. final InstructionList il = new InstructionList();
  842. final MethodGenerator toplevel =
  843. new MethodGenerator(ACC_PUBLIC,
  844. com.sun.org.apache.bcel.internal.generic.Type.VOID,
  845. argTypes, argNames,
  846. "topLevel", _className, il,
  847. classGen.getConstantPool());
  848. toplevel.addException("com.sun.org.apache.xalan.internal.xsltc.TransletException");
  849. // Define and initialize 'current' variable with the root node
  850. final LocalVariableGen current =
  851. toplevel.addLocalVariable("current",
  852. com.sun.org.apache.bcel.internal.generic.Type.INT,
  853. il.getEnd(), null);
  854. final int setFilter = cpg.addInterfaceMethodref(DOM_INTF,
  855. "setFilter",
  856. "(Lcom/sun/org/apache/xalan/internal/xsltc/StripFilter;)V");
  857. il.append(new PUSH(cpg, DTM.ROOT_NODE));
  858. il.append(new ISTORE(current.getIndex()));
  859. // Resolve any forward referenes and translate global variables/params
  860. _globals = resolveReferences(_globals);
  861. final int count = _globals.size();
  862. for (int i = 0; i < count; i++) {
  863. final VariableBase var = (VariableBase)_globals.elementAt(i);
  864. var.translate(classGen,toplevel);
  865. }
  866. // Compile code for other top-level elements
  867. Vector whitespaceRules = new Vector();
  868. while (elements.hasMoreElements()) {
  869. final Object element = elements.nextElement();
  870. // xsl:decimal-format
  871. if (element instanceof DecimalFormatting) {
  872. ((DecimalFormatting)element).translate(classGen,toplevel);
  873. }
  874. // xsl:strip/preserve-space
  875. else if (element instanceof Whitespace) {
  876. whitespaceRules.addAll(((Whitespace)element).getRules());
  877. }
  878. }
  879. // Translate all whitespace strip/preserve rules
  880. if (whitespaceRules.size() > 0) {
  881. Whitespace.translateRules(whitespaceRules,classGen);
  882. }
  883. if (classGen.containsMethod(STRIP_SPACE, STRIP_SPACE_PARAMS) != null) {
  884. il.append(toplevel.loadDOM());
  885. il.append(classGen.loadTranslet());
  886. il.append(new INVOKEINTERFACE(setFilter, 2));
  887. }
  888. il.append(RETURN);
  889. // Compute max locals + stack and add method to class
  890. toplevel.stripAttributes(true);
  891. toplevel.setMaxLocals();
  892. toplevel.setMaxStack();
  893. toplevel.removeNOPs();
  894. classGen.addMethod(toplevel.getMethod());
  895. return("("+DOM_INTF_SIG+NODE_ITERATOR_SIG+TRANSLET_OUTPUT_SIG+")V");
  896. }
  897. /**
  898. * This method returns a vector with variables in the order in
  899. * which they are to be compiled. The order is determined by the
  900. * dependencies between them and the order in which they were defined
  901. * in the stylesheet. The first step is to close the input vector under
  902. * the dependence relation (this is usually needed when variables are
  903. * defined inside other variables in a RTF).
  904. */
  905. private Vector resolveReferences(Vector input) {
  906. // Make sure that the vector 'input' is closed
  907. for (int i = 0; i < input.size(); i++) {
  908. final VariableBase var = (VariableBase) input.elementAt(i);
  909. final Vector dep = var.getDependencies();
  910. final int depSize = (dep != null) ? dep.size() : 0;
  911. for (int j = 0; j < depSize; j++) {
  912. final VariableBase depVar = (VariableBase) dep.elementAt(j);
  913. if (!input.contains(depVar)) {
  914. input.addElement(depVar);
  915. }
  916. }
  917. }
  918. /* DEBUG CODE - INGORE
  919. for (int i = 0; i < input.size(); i++) {
  920. final VariableBase var = (VariableBase) input.elementAt(i);
  921. System.out.println("var = " + var);
  922. }
  923. System.out.println("=================================");
  924. */
  925. Vector result = new Vector();
  926. while (input.size() > 0) {
  927. boolean changed = false;
  928. for (int i = 0; i < input.size(); ) {
  929. final VariableBase var = (VariableBase)input.elementAt(i);
  930. final Vector dep = var.getDependencies();
  931. if (dep == null || result.containsAll(dep)) {
  932. result.addElement(var);
  933. input.remove(i);
  934. changed = true;
  935. }
  936. else {
  937. i++;
  938. }
  939. }
  940. // If nothing was changed in this pass then we have a circular ref
  941. if (!changed) {
  942. ErrorMsg err = new ErrorMsg(ErrorMsg.CIRCULAR_VARIABLE_ERR,
  943. input.toString(), this);
  944. getParser().reportError(Constants.ERROR, err);
  945. return(result);
  946. }
  947. }
  948. /* DEBUG CODE - INGORE
  949. System.out.println("=================================");
  950. for (int i = 0; i < result.size(); i++) {
  951. final VariableBase var = (VariableBase) result.elementAt(i);
  952. System.out.println("var = " + var);
  953. }
  954. */
  955. return result;
  956. }
  957. /**
  958. * Compile a buildKeys() method into the output class. This method is
  959. * called from transform() to handle build all indexes needed by key().
  960. */
  961. private String compileBuildKeys(ClassGenerator classGen) {
  962. final ConstantPoolGen cpg = classGen.getConstantPool();
  963. final com.sun.org.apache.bcel.internal.generic.Type[] argTypes = {
  964. Util.getJCRefType(DOM_INTF_SIG),
  965. Util.getJCRefType(NODE_ITERATOR_SIG),
  966. Util.getJCRefType(TRANSLET_OUTPUT_SIG),
  967. com.sun.org.apache.bcel.internal.generic.Type.INT
  968. };
  969. final String[] argNames = {
  970. DOCUMENT_PNAME, ITERATOR_PNAME, TRANSLET_OUTPUT_PNAME, "current"
  971. };
  972. final InstructionList il = new InstructionList();
  973. final MethodGenerator buildKeys =
  974. new MethodGenerator(ACC_PUBLIC,
  975. com.sun.org.apache.bcel.internal.generic.Type.VOID,
  976. argTypes, argNames,
  977. "buildKeys", _className, il,
  978. classGen.getConstantPool());
  979. buildKeys.addException("com.sun.org.apache.xalan.internal.xsltc.TransletException");
  980. final Enumeration elements = elements();
  981. // Compile code for other top-level elements
  982. while (elements.hasMoreElements()) {
  983. // xsl:key
  984. final Object element = elements.nextElement();
  985. if (element instanceof Key) {
  986. final Key key = (Key)element;
  987. key.translate(classGen, buildKeys);
  988. _keys.put(key.getName(),key);
  989. }
  990. }
  991. il.append(RETURN);
  992. // Compute max locals + stack and add method to class
  993. buildKeys.stripAttributes(true);
  994. buildKeys.setMaxLocals();
  995. buildKeys.setMaxStack();
  996. buildKeys.removeNOPs();
  997. classGen.addMethod(buildKeys.getMethod());
  998. return("("+DOM_INTF_SIG+NODE_ITERATOR_SIG+TRANSLET_OUTPUT_SIG+"I)V");
  999. }
  1000. /**
  1001. * Compile transform() into the output class. This method is used to
  1002. * initialize global variables and global parameters. The current node
  1003. * is set to be the document's root node.
  1004. */
  1005. private void compileTransform(ClassGenerator classGen) {
  1006. final ConstantPoolGen cpg = classGen.getConstantPool();
  1007. /*
  1008. * Define the the method transform with the following signature:
  1009. * void transform(DOM, NodeIterator, HandlerBase)
  1010. */
  1011. final com.sun.org.apache.bcel.internal.generic.Type[] argTypes =
  1012. new com.sun.org.apache.bcel.internal.generic.Type[3];
  1013. argTypes[0] = Util.getJCRefType(DOM_INTF_SIG);
  1014. argTypes[1] = Util.getJCRefType(NODE_ITERATOR_SIG);
  1015. argTypes[2] = Util.getJCRefType(TRANSLET_OUTPUT_SIG);
  1016. final String[] argNames = new String[3];
  1017. argNames[0] = DOCUMENT_PNAME;
  1018. argNames[1] = ITERATOR_PNAME;
  1019. argNames[2] = TRANSLET_OUTPUT_PNAME;
  1020. final InstructionList il = new InstructionList();
  1021. final MethodGenerator transf =
  1022. new MethodGenerator(ACC_PUBLIC,
  1023. com.sun.org.apache.bcel.internal.generic.Type.VOID,
  1024. argTypes, argNames,
  1025. "transform",
  1026. _className,
  1027. il,
  1028. classGen.getConstantPool());
  1029. transf.addException("com.sun.org.apache.xalan.internal.xsltc.TransletException");
  1030. // Define and initialize current with the root node
  1031. final LocalVariableGen current =
  1032. transf.addLocalVariable("current",
  1033. com.sun.org.apache.bcel.internal.generic.Type.INT,
  1034. il.getEnd(), null);
  1035. final String applyTemplatesSig = classGen.getApplyTemplatesSig();
  1036. final int applyTemplates = cpg.addMethodref(getClassName(),
  1037. "applyTemplates",
  1038. applyTemplatesSig);
  1039. final int domField = cpg.addFieldref(getClassName(),
  1040. DOM_FIELD,
  1041. DOM_INTF_SIG);
  1042. // push translet for PUTFIELD
  1043. il.append(classGen.loadTranslet());
  1044. // prepare appropriate DOM implementation
  1045. if (isMultiDocument()) {
  1046. il.append(new NEW(cpg.addClass(MULTI_DOM_CLASS)));
  1047. il.append(DUP);
  1048. }
  1049. il.append(classGen.loadTranslet());
  1050. il.append(transf.loadDOM());
  1051. il.append(new INVOKEVIRTUAL(cpg.addMethodref(TRANSLET_CLASS,
  1052. "makeDOMAdapter",
  1053. "("+DOM_INTF_SIG+")"+
  1054. DOM_ADAPTER_SIG)));
  1055. // DOMAdapter is on the stack
  1056. if (isMultiDocument()) {
  1057. final int init = cpg.addMethodref(MULTI_DOM_CLASS,
  1058. "<init>",
  1059. "("+DOM_INTF_SIG+")V");
  1060. il.append(new INVOKESPECIAL(init));
  1061. // MultiDOM is on the stack
  1062. }
  1063. //store to _dom variable
  1064. il.append(new PUTFIELD(domField));
  1065. // continue with globals initialization
  1066. il.append(new PUSH(cpg, DTM.ROOT_NODE));
  1067. il.append(new ISTORE(current.getIndex()));
  1068. // Transfer the output settings to the output post-processor
  1069. il.append(classGen.loadTranslet());
  1070. il.append(transf.loadHandler());
  1071. final int index = cpg.addMethodref(TRANSLET_CLASS,
  1072. "transferOutputSettings",
  1073. "("+OUTPUT_HANDLER_SIG+")V");
  1074. il.append(new INVOKEVIRTUAL(index));
  1075. // Compile buildKeys -- TODO: omit if not needed
  1076. final String keySig = compileBuildKeys(classGen);
  1077. final int keyIdx = cpg.addMethodref(getClassName(),
  1078. "buildKeys", keySig);
  1079. il.append(classGen.loadTranslet()); // The 'this' pointer
  1080. il.append(classGen.loadTranslet());
  1081. il.append(new GETFIELD(domField)); // The DOM reference
  1082. il.append(transf.loadIterator()); // Not really used, but...
  1083. il.append(transf.loadHandler()); // The output handler
  1084. il.append(new PUSH(cpg, DTM.ROOT_NODE)); // Start with the root node
  1085. il.append(new INVOKEVIRTUAL(keyIdx));
  1086. // Look for top-level elements that need handling
  1087. final Enumeration toplevel = elements();
  1088. if ((_globals.size() > 0) || (toplevel.hasMoreElements())) {
  1089. // Compile method for handling top-level elements
  1090. final String topLevelSig = compileTopLevel(classGen, toplevel);
  1091. // Get a reference to that method
  1092. final int topLevelIdx = cpg.addMethodref(getClassName(),
  1093. "topLevel",
  1094. topLevelSig);
  1095. // Push all parameters on the stack and call topLevel()
  1096. il.append(classGen.loadTranslet()); // The 'this' pointer
  1097. il.append(classGen.loadTranslet());
  1098. il.append(new GETFIELD(domField)); // The DOM reference
  1099. il.append(transf.loadIterator());
  1100. il.append(transf.loadHandler()); // The output handler
  1101. il.append(new INVOKEVIRTUAL(topLevelIdx));
  1102. }
  1103. // start document
  1104. il.append(transf.loadHandler());
  1105. il.append(transf.startDocument());
  1106. // push first arg for applyTemplates
  1107. il.append(classGen.loadTranslet());
  1108. // push translet for GETFIELD to get DOM arg
  1109. il.append(classGen.loadTranslet());
  1110. il.append(new GETFIELD(domField));
  1111. // push remaining 2 args
  1112. il.append(transf.loadIterator());
  1113. il.append(transf.loadHandler());
  1114. il.append(new INVOKEVIRTUAL(applyTemplates));
  1115. // endDocument
  1116. il.append(transf.loadHandler());
  1117. il.append(transf.endDocument());
  1118. il.append(RETURN);
  1119. // Compute max locals + stack and add method to class
  1120. transf.stripAttributes(true);
  1121. transf.setMaxLocals();
  1122. transf.setMaxStack();
  1123. transf.removeNOPs();
  1124. classGen.addMethod(transf.getMethod());
  1125. }
  1126. /**
  1127. * Peephole optimization: Remove sequences of [ALOAD, POP].
  1128. */
  1129. private void peepHoleOptimization(MethodGenerator methodGen) {
  1130. final String pattern = "`aload'`pop'`instruction'";
  1131. final InstructionList il = methodGen.getInstructionList();
  1132. final InstructionFinder find = new InstructionFinder(il);
  1133. for(Iterator iter=find.search(pattern); iter.hasNext(); ) {
  1134. InstructionHandle[] match = (InstructionHandle[])iter.next();
  1135. try {
  1136. il.delete(match[0], match[1]);
  1137. }
  1138. catch (TargetLostException e) {
  1139. // TODO: move target down into the list
  1140. }
  1141. }
  1142. }
  1143. public int addParam(Param param) {
  1144. _globals.addElement(param);
  1145. return _globals.size() - 1;
  1146. }
  1147. public int addVariable(Variable global) {
  1148. _globals.addElement(global);
  1149. return _globals.size() - 1;
  1150. }
  1151. public void display(int indent) {
  1152. indent(indent);
  1153. Util.println("Stylesheet");
  1154. displayContents(indent + IndentIncrement);
  1155. }
  1156. // do we need this wrapper ?????
  1157. public String getNamespace(String prefix) {
  1158. return lookupNamespace(prefix);
  1159. }
  1160. public String getClassName() {
  1161. return _className;
  1162. }
  1163. public Vector getTemplates() {
  1164. return _templates;
  1165. }
  1166. public Vector getAllValidTemplates() {
  1167. // Return templates if no imported/included stylesheets
  1168. if (_includedStylesheets == null) {
  1169. return _templates;
  1170. }
  1171. // Is returned value cached?
  1172. if (_allValidTemplates == null) {
  1173. Vector templates = new Vector();
  1174. int size = _includedStylesheets.size();
  1175. for (int i = 0; i < size; i++) {
  1176. Stylesheet included =(Stylesheet)_includedStylesheets.elementAt(i);
  1177. templates.addAll(included.getAllValidTemplates());
  1178. }
  1179. templates.addAll(_templates);
  1180. // Cache results in top-level stylesheet only
  1181. if (_parentStylesheet != null) {
  1182. return templates;
  1183. }
  1184. _allValidTemplates = templates;
  1185. }
  1186. return _allValidTemplates;
  1187. }
  1188. protected void addTemplate(Template template) {
  1189. _templates.addElement(template);
  1190. }
  1191. }