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: LiteralElement.java,v 1.25 2004/02/24 03:55:47 zongaro Exp $
  18. */
  19. package com.sun.org.apache.xalan.internal.xsltc.compiler;
  20. import java.util.Enumeration;
  21. import java.util.Hashtable;
  22. import java.util.Vector;
  23. import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
  24. import com.sun.org.apache.bcel.internal.generic.InstructionList;
  25. import com.sun.org.apache.bcel.internal.generic.PUSH;
  26. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
  27. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
  28. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
  29. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
  30. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
  31. import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
  32. import com.sun.org.apache.xml.internal.serializer.ElemDesc;
  33. import com.sun.org.apache.xml.internal.serializer.ToHTMLStream;
  34. /**
  35. * @author Jacek Ambroziak
  36. * @author Santiago Pericas-Geertsen
  37. * @author Morten Jorgensen
  38. */
  39. final class LiteralElement extends Instruction {
  40. private String _name;
  41. private LiteralElement _literalElemParent;
  42. private Vector _attributeElements = null;
  43. private Hashtable _accessedPrefixes = null;
  44. // True if all attributes of this LRE are unique, i.e. they all have
  45. // different names. This flag is set to false if some attribute
  46. // names are not known at compile time.
  47. private boolean _allAttributesUnique = false;
  48. private final static String XMLNS_STRING = "xmlns";
  49. /**
  50. * Returns the QName for this literal element
  51. */
  52. public QName getName() {
  53. return _qname;
  54. }
  55. /**
  56. * Displays the contents of this literal element
  57. */
  58. public void display(int indent) {
  59. indent(indent);
  60. Util.println("LiteralElement name = " + _name);
  61. displayContents(indent + IndentIncrement);
  62. }
  63. /**
  64. * Returns the namespace URI for which a prefix is pointing to
  65. */
  66. private String accessedNamespace(String prefix) {
  67. if (_accessedPrefixes == null)
  68. return(null);
  69. else
  70. return((String)_accessedPrefixes.get(prefix));
  71. }
  72. /**
  73. * Method used to keep track of what namespaces that are references by
  74. * this literal element and its attributes. The output must contain a
  75. * definition for each namespace, so we stuff them in a hashtable.
  76. */
  77. public void registerNamespace(String prefix, String uri,
  78. SymbolTable stable, boolean declared) {
  79. // Check if the parent has a declaration for this namespace
  80. if (_literalElemParent != null) {
  81. final String parentUri = _literalElemParent.accessedNamespace(prefix);
  82. if (parentUri == null) {
  83. _literalElemParent.registerNamespace(prefix, uri, stable, declared);
  84. return;
  85. }
  86. if (parentUri.equals(uri)) return;
  87. }
  88. // Check if we have any declared namesaces
  89. if (_accessedPrefixes == null) {
  90. _accessedPrefixes = new Hashtable();
  91. }
  92. else {
  93. if (!declared) {
  94. // Check if this node has a declaration for this namespace
  95. final String old = (String)_accessedPrefixes.get(prefix);
  96. if (old != null) {
  97. if (old.equals(uri))
  98. return;
  99. else
  100. prefix = stable.generateNamespacePrefix();
  101. }
  102. }
  103. }
  104. if (!prefix.equals("xml")) {
  105. _accessedPrefixes.put(prefix,uri);
  106. }
  107. }
  108. /**
  109. * Translates the prefix of a QName according to the rules set in
  110. * the attributes of xsl:stylesheet. Also registers a QName to assure
  111. * that the output element contains the necessary namespace declarations.
  112. */
  113. private String translateQName(QName qname, SymbolTable stable) {
  114. // Break up the QName and get prefix:localname strings
  115. String localname = qname.getLocalPart();
  116. String prefix = qname.getPrefix();
  117. // Treat default namespace as "" and not null
  118. if (prefix == null)
  119. prefix = Constants.EMPTYSTRING;
  120. else if (prefix.equals(XMLNS_STRING))
  121. return(XMLNS_STRING);
  122. // Check if we must translate the prefix
  123. final String alternative = stable.lookupPrefixAlias(prefix);
  124. if (alternative != null) {
  125. stable.excludeNamespaces(prefix);
  126. prefix = alternative;
  127. }
  128. // Get the namespace this prefix refers to
  129. String uri = lookupNamespace(prefix);
  130. if (uri == null) return(localname);
  131. // Register the namespace as accessed
  132. registerNamespace(prefix, uri, stable, false);
  133. // Construct the new name for the element (may be unchanged)
  134. if (prefix != Constants.EMPTYSTRING)
  135. return(prefix+":"+localname);
  136. else
  137. return(localname);
  138. }
  139. /**
  140. * Add an attribute to this element
  141. */
  142. public void addAttribute(SyntaxTreeNode attribute) {
  143. if (_attributeElements == null) {
  144. _attributeElements = new Vector(2);
  145. }
  146. _attributeElements.add(attribute);
  147. }
  148. /**
  149. * Set the first attribute of this element
  150. */
  151. public void setFirstAttribute(SyntaxTreeNode attribute) {
  152. if (_attributeElements == null) {
  153. _attributeElements = new Vector(2);
  154. }
  155. _attributeElements.insertElementAt(attribute,0);
  156. }
  157. /**
  158. * Type-check the contents of this element. The element itself does not
  159. * need any type checking as it leaves nothign on the JVM's stack.
  160. */
  161. public Type typeCheck(SymbolTable stable) throws TypeCheckError {
  162. // Type-check all attributes
  163. if (_attributeElements != null) {
  164. final int count = _attributeElements.size();
  165. for (int i = 0; i < count; i++) {
  166. SyntaxTreeNode node =
  167. (SyntaxTreeNode)_attributeElements.elementAt(i);
  168. node.typeCheck(stable);
  169. }
  170. }
  171. typeCheckContents(stable);
  172. return Type.Void;
  173. }
  174. /**
  175. * This method starts at a given node, traverses all namespace mappings,
  176. * and assembles a list of all prefixes that (for the given node) maps
  177. * to _ANY_ namespace URI. Used by literal result elements to determine
  178. */
  179. public Enumeration getNamespaceScope(SyntaxTreeNode node) {
  180. Hashtable all = new Hashtable();
  181. while (node != null) {
  182. Hashtable mapping = node.getPrefixMapping();
  183. if (mapping != null) {
  184. Enumeration prefixes = mapping.keys();
  185. while (prefixes.hasMoreElements()) {
  186. String prefix = (String)prefixes.nextElement();
  187. if (!all.containsKey(prefix)) {
  188. all.put(prefix, mapping.get(prefix));
  189. }
  190. }
  191. }
  192. node = node.getParent();
  193. }
  194. return(all.keys());
  195. }
  196. /**
  197. * Determines the final QName for the element and its attributes.
  198. * Registers all namespaces that are used by the element/attributes
  199. */
  200. public void parseContents(Parser parser) {
  201. final SymbolTable stable = parser.getSymbolTable();
  202. stable.setCurrentNode(this);
  203. // Find the closest literal element ancestor (if there is one)
  204. SyntaxTreeNode _literalElemParent = getParent();
  205. while (_literalElemParent != null && !(_literalElemParent instanceof LiteralElement)) {
  206. _literalElemParent = _literalElemParent.getParent();
  207. }
  208. if (!(_literalElemParent instanceof LiteralElement)) {
  209. _literalElemParent = null;
  210. }
  211. _name = translateQName(_qname, stable);
  212. // Process all attributes and register all namespaces they use
  213. final int count = _attributes.getLength();
  214. for (int i = 0; i < count; i++) {
  215. final QName qname = parser.getQName(_attributes.getQName(i));
  216. final String uri = qname.getNamespace();
  217. final String val = _attributes.getValue(i);
  218. // Handle xsl:use-attribute-sets. Attribute sets are placed first
  219. // in the vector or attributes to make sure that later local
  220. // attributes can override an attributes in the set.
  221. if (qname == parser.getUseAttributeSets()) {
  222. if (!Util.isValidQNames(val)) {
  223. ErrorMsg err = new ErrorMsg(ErrorMsg.INVALID_QNAME_ERR, val, this);
  224. parser.reportError(Constants.ERROR, err);
  225. }
  226. setFirstAttribute(new UseAttributeSets(val, parser));
  227. }
  228. // Handle xsl:extension-element-prefixes
  229. else if (qname == parser.getExtensionElementPrefixes()) {
  230. stable.excludeNamespaces(val);
  231. }
  232. // Handle xsl:exclude-result-prefixes
  233. else if (qname == parser.getExcludeResultPrefixes()) {
  234. stable.excludeNamespaces(val);
  235. }
  236. else {
  237. // Ignore special attributes (e.g. xmlns:prefix and xmlns)
  238. final String prefix = qname.getPrefix();
  239. if (prefix != null && prefix.equals(XMLNS_PREFIX) ||
  240. prefix == null && qname.getLocalPart().equals("xmlns") ||
  241. uri != null && uri.equals(XSLT_URI))
  242. {
  243. continue;
  244. }
  245. // Handle all other literal attributes
  246. final String name = translateQName(qname, stable);
  247. LiteralAttribute attr = new LiteralAttribute(name, val, parser, this);
  248. addAttribute(attr);
  249. attr.setParent(this);
  250. attr.parseContents(parser);
  251. }
  252. }
  253. // Register all namespaces that are in scope, except for those that
  254. // are listed in the xsl:stylesheet element's *-prefixes attributes
  255. final Enumeration include = getNamespaceScope(this);
  256. while (include.hasMoreElements()) {
  257. final String prefix = (String)include.nextElement();
  258. if (!prefix.equals("xml")) {
  259. final String uri = lookupNamespace(prefix);
  260. if (uri != null && !stable.isExcludedNamespace(uri)) {
  261. registerNamespace(prefix, uri, stable, true);
  262. }
  263. }
  264. }
  265. parseChildren(parser);
  266. // Process all attributes and register all namespaces they use
  267. for (int i = 0; i < count; i++) {
  268. final QName qname = parser.getQName(_attributes.getQName(i));
  269. final String val = _attributes.getValue(i);
  270. // Handle xsl:extension-element-prefixes
  271. if (qname == parser.getExtensionElementPrefixes()) {
  272. stable.unExcludeNamespaces(val);
  273. }
  274. // Handle xsl:exclude-result-prefixes
  275. else if (qname == parser.getExcludeResultPrefixes()) {
  276. stable.unExcludeNamespaces(val);
  277. }
  278. }
  279. }
  280. protected boolean contextDependent() {
  281. return dependentContents();
  282. }
  283. /**
  284. * Compiles code that emits the literal element to the output handler,
  285. * first the start tag, then namespace declaration, then attributes,
  286. * then the element contents, and then the element end tag. Since the
  287. * value of an attribute may depend on a variable, variables must be
  288. * compiled first.
  289. */
  290. public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
  291. final ConstantPoolGen cpg = classGen.getConstantPool();
  292. final InstructionList il = methodGen.getInstructionList();
  293. // Check whether all attributes are unique.
  294. _allAttributesUnique = checkAttributesUnique();
  295. // Compile code to emit element start tag
  296. il.append(methodGen.loadHandler());
  297. il.append(new PUSH(cpg, _name));
  298. il.append(DUP2); // duplicate these 2 args for endElement
  299. il.append(methodGen.startElement());
  300. // The value of an attribute may depend on a (sibling) variable
  301. int j=0;
  302. while (j < elementCount())
  303. {
  304. final SyntaxTreeNode item = (SyntaxTreeNode) elementAt(j);
  305. if (item instanceof Variable) {
  306. item.translate(classGen, methodGen);
  307. removeElement(item); // avoid translating it twice
  308. /* When removing an element we do not increment j
  309. * but the removal will reduce the value of elementCount()
  310. * so this loop WILL end. The next iteration will process
  311. * elementAt(j), but with the old element removed
  312. * we are actually processing the next element.
  313. */
  314. }
  315. else
  316. j++;
  317. }
  318. // Compile code to emit namespace attributes
  319. if (_accessedPrefixes != null) {
  320. boolean declaresDefaultNS = false;
  321. Enumeration e = _accessedPrefixes.keys();
  322. while (e.hasMoreElements()) {
  323. final String prefix = (String)e.nextElement();
  324. final String uri = (String)_accessedPrefixes.get(prefix);
  325. if (uri != Constants.EMPTYSTRING ||
  326. prefix != Constants.EMPTYSTRING)
  327. {
  328. if (prefix == Constants.EMPTYSTRING) {
  329. declaresDefaultNS = true;
  330. }
  331. il.append(methodGen.loadHandler());
  332. il.append(new PUSH(cpg,prefix));
  333. il.append(new PUSH(cpg,uri));
  334. il.append(methodGen.namespace());
  335. }
  336. }
  337. /*
  338. * If our XslElement parent redeclares the default NS, and this
  339. * element doesn't, it must be redeclared one more time.
  340. */
  341. if (!declaresDefaultNS && (_parent instanceof XslElement)
  342. && ((XslElement) _parent).declaresDefaultNS())
  343. {
  344. il.append(methodGen.loadHandler());
  345. il.append(new PUSH(cpg, Constants.EMPTYSTRING));
  346. il.append(new PUSH(cpg, Constants.EMPTYSTRING));
  347. il.append(methodGen.namespace());
  348. }
  349. }
  350. // Output all attributes
  351. if (_attributeElements != null) {
  352. final int count = _attributeElements.size();
  353. for (int i = 0; i < count; i++) {
  354. SyntaxTreeNode node =
  355. (SyntaxTreeNode)_attributeElements.elementAt(i);
  356. if (!(node instanceof XslAttribute)) {
  357. node.translate(classGen, methodGen);
  358. }
  359. }
  360. }
  361. // Compile code to emit attributes and child elements
  362. translateContents(classGen, methodGen);
  363. // Compile code to emit element end tag
  364. il.append(methodGen.endElement());
  365. }
  366. /**
  367. * Return true if the output method is html.
  368. */
  369. private boolean isHTMLOutput() {
  370. return getStylesheet().getOutputMethod() == Stylesheet.HTML_OUTPUT;
  371. }
  372. /**
  373. * Return the ElemDesc object for an HTML element.
  374. * Return null if the output method is not HTML or this is not a
  375. * valid HTML element.
  376. */
  377. public ElemDesc getElemDesc() {
  378. if (isHTMLOutput()) {
  379. return ToHTMLStream.getElemDesc(_name);
  380. }
  381. else
  382. return null;
  383. }
  384. /**
  385. * Return true if all attributes of this LRE have unique names.
  386. */
  387. public boolean allAttributesUnique() {
  388. return _allAttributesUnique;
  389. }
  390. /**
  391. * Check whether all attributes are unique.
  392. */
  393. private boolean checkAttributesUnique() {
  394. boolean hasHiddenXslAttribute = canProduceAttributeNodes(this, true);
  395. if (hasHiddenXslAttribute)
  396. return false;
  397. if (_attributeElements != null) {
  398. int numAttrs = _attributeElements.size();
  399. Hashtable attrsTable = null;
  400. for (int i = 0; i < numAttrs; i++) {
  401. SyntaxTreeNode node = (SyntaxTreeNode)_attributeElements.elementAt(i);
  402. if (node instanceof UseAttributeSets) {
  403. return false;
  404. }
  405. else if (node instanceof XslAttribute) {
  406. if (attrsTable == null) {
  407. attrsTable = new Hashtable();
  408. for (int k = 0; k < i; k++) {
  409. SyntaxTreeNode n = (SyntaxTreeNode)_attributeElements.elementAt(k);
  410. if (n instanceof LiteralAttribute) {
  411. LiteralAttribute literalAttr = (LiteralAttribute)n;
  412. attrsTable.put(literalAttr.getName(), literalAttr);
  413. }
  414. }
  415. }
  416. XslAttribute xslAttr = (XslAttribute)node;
  417. AttributeValue attrName = xslAttr.getName();
  418. if (attrName instanceof AttributeValueTemplate) {
  419. return false;
  420. }
  421. else if (attrName instanceof SimpleAttributeValue) {
  422. SimpleAttributeValue simpleAttr = (SimpleAttributeValue)attrName;
  423. String name = simpleAttr.toString();
  424. if (name != null && attrsTable.get(name) != null)
  425. return false;
  426. else if (name != null) {
  427. attrsTable.put(name, xslAttr);
  428. }
  429. }
  430. }
  431. }
  432. }
  433. return true;
  434. }
  435. /**
  436. * Return true if the instructions under the given SyntaxTreeNode can produce attribute nodes
  437. * to an element. Only return false when we are sure that no attribute node is produced.
  438. * Return true if we are not sure. If the flag ignoreXslAttribute is true, the direct
  439. * <xsl:attribute> children of the current node are not included in the check.
  440. */
  441. private boolean canProduceAttributeNodes(SyntaxTreeNode node, boolean ignoreXslAttribute) {
  442. Vector contents = node.getContents();
  443. int size = contents.size();
  444. for (int i = 0; i < size; i++) {
  445. SyntaxTreeNode child = (SyntaxTreeNode)contents.elementAt(i);
  446. if (child instanceof Text) {
  447. Text text = (Text)child;
  448. if (text.isIgnore())
  449. continue;
  450. else
  451. return false;
  452. }
  453. // Cannot add an attribute to an element after children have been added to it.
  454. // We can safely return false when the instruction can produce an output node.
  455. else if (child instanceof LiteralElement
  456. || child instanceof ValueOf
  457. || child instanceof XslElement
  458. || child instanceof Comment
  459. || child instanceof Number
  460. || child instanceof ProcessingInstruction)
  461. return false;
  462. else if (child instanceof XslAttribute) {
  463. if (ignoreXslAttribute)
  464. continue;
  465. else
  466. return true;
  467. }
  468. // In general, there is no way to check whether <xsl:call-template> or
  469. // <xsl:apply-templates> can produce attribute nodes. <xsl:copy> and
  470. // <xsl:copy-of> can also copy attribute nodes to an element. Return
  471. // true in those cases to be safe.
  472. else if (child instanceof CallTemplate
  473. || child instanceof ApplyTemplates
  474. || child instanceof Copy
  475. || child instanceof CopyOf)
  476. return true;
  477. else if ((child instanceof If
  478. || child instanceof ForEach)
  479. && canProduceAttributeNodes(child, false)) {
  480. return true;
  481. }
  482. else if (child instanceof Choose) {
  483. Vector chooseContents = child.getContents();
  484. int num = chooseContents.size();
  485. for (int k = 0; k < num; k++) {
  486. SyntaxTreeNode chooseChild = (SyntaxTreeNode)chooseContents.elementAt(k);
  487. if (chooseChild instanceof When || chooseChild instanceof Otherwise) {
  488. if (canProduceAttributeNodes(chooseChild, false))
  489. return true;
  490. }
  491. }
  492. }
  493. }
  494. return false;
  495. }
  496. }