1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 1999 The Apache Software Foundation. All rights
  6. * reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The end-user documentation included with the redistribution,
  21. * if any, must include the following acknowledgment:
  22. * "This product includes software developed by the
  23. * Apache Software Foundation (http://www.apache.org/)."
  24. * Alternately, this acknowledgment may appear in the software itself,
  25. * if and wherever such third-party acknowledgments normally appear.
  26. *
  27. * 4. The names "Xalan" and "Apache Software Foundation" must
  28. * not be used to endorse or promote products derived from this
  29. * software without prior written permission. For written
  30. * permission, please contact apache@apache.org.
  31. *
  32. * 5. Products derived from this software may not be called "Apache",
  33. * nor may "Apache" appear in their name, without prior written
  34. * permission of the Apache Software Foundation.
  35. *
  36. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  37. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  38. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  40. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  43. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  44. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  45. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  46. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47. * SUCH DAMAGE.
  48. * ====================================================================
  49. *
  50. * This software consists of voluntary contributions made by many
  51. * individuals on behalf of the Apache Software Foundation and was
  52. * originally based on software copyright (c) 1999, Lotus
  53. * Development Corporation., http://www.lotus.com. For more
  54. * information on the Apache Software Foundation, please see
  55. * <http://www.apache.org/>.
  56. */
  57. package org.apache.xalan.templates;
  58. //import org.w3c.dom.*;
  59. import org.apache.xml.dtm.DTM;
  60. import org.xml.sax.*;
  61. import org.apache.xpath.*;
  62. import org.apache.xml.utils.QName;
  63. import org.apache.xalan.res.XSLTErrorResources;
  64. import org.apache.xalan.transformer.TransformerImpl;
  65. import org.apache.xalan.transformer.ResultTreeHandler;
  66. import javax.xml.transform.TransformerException;
  67. /**
  68. * <meta name="usage" content="advanced"/>
  69. * Implement xsl:element
  70. * <pre>
  71. * <!ELEMENT xsl:element %template;>
  72. * <!ATTLIST xsl:element
  73. * name %avt; #REQUIRED
  74. * namespace %avt; #IMPLIED
  75. * use-attribute-sets %qnames; #IMPLIED
  76. * %space-att;
  77. * >
  78. * </pre>
  79. * @see <a href="http://www.w3.org/TR/xslt#section-Creating-Elements-with-xsl:element">XXX in XSLT Specification</a>
  80. */
  81. public class ElemElement extends ElemUse
  82. {
  83. /**
  84. * The name attribute is interpreted as an attribute value template.
  85. * It is an error if the string that results from instantiating the
  86. * attribute value template is not a QName.
  87. * @serial
  88. */
  89. protected AVT m_name_avt = null;
  90. /**
  91. * Set the "name" attribute.
  92. * The name attribute is interpreted as an attribute value template.
  93. * It is an error if the string that results from instantiating the
  94. * attribute value template is not a QName.
  95. *
  96. * @param v Name attribute to set for this element
  97. */
  98. public void setName(AVT v)
  99. {
  100. m_name_avt = v;
  101. }
  102. /**
  103. * Get the "name" attribute.
  104. * The name attribute is interpreted as an attribute value template.
  105. * It is an error if the string that results from instantiating the
  106. * attribute value template is not a QName.
  107. *
  108. * @return Name attribute for this element
  109. */
  110. public AVT getName()
  111. {
  112. return m_name_avt;
  113. }
  114. /**
  115. * If the namespace attribute is present, then it also is interpreted
  116. * as an attribute value template. The string that results from
  117. * instantiating the attribute value template should be a URI reference.
  118. * It is not an error if the string is not a syntactically legal URI reference.
  119. * @serial
  120. */
  121. protected AVT m_namespace_avt = null;
  122. /**
  123. * Set the "namespace" attribute.
  124. * If the namespace attribute is present, then it also is interpreted
  125. * as an attribute value template. The string that results from
  126. * instantiating the attribute value template should be a URI reference.
  127. * It is not an error if the string is not a syntactically legal URI reference.
  128. *
  129. * @param v NameSpace attribute to set for this element
  130. */
  131. public void setNamespace(AVT v)
  132. {
  133. m_namespace_avt = v;
  134. }
  135. /**
  136. * Get the "namespace" attribute.
  137. * If the namespace attribute is present, then it also is interpreted
  138. * as an attribute value template. The string that results from
  139. * instantiating the attribute value template should be a URI reference.
  140. * It is not an error if the string is not a syntactically legal URI reference.
  141. *
  142. * @return Namespace attribute for this element
  143. */
  144. public AVT getNamespace()
  145. {
  146. return m_namespace_avt;
  147. }
  148. /**
  149. * This function is called after everything else has been
  150. * recomposed, and allows the template to set remaining
  151. * values that may be based on some other property that
  152. * depends on recomposition.
  153. */
  154. public void compose(StylesheetRoot sroot) throws TransformerException
  155. {
  156. super.compose(sroot);
  157. StylesheetRoot.ComposeState cstate = sroot.getComposeState();
  158. java.util.Vector vnames = cstate.getVariableNames();
  159. if(null != m_name_avt)
  160. m_name_avt.fixupVariables(vnames, cstate.getGlobalsSize());
  161. if(null != m_namespace_avt)
  162. m_namespace_avt.fixupVariables(vnames, cstate.getGlobalsSize());
  163. }
  164. /**
  165. * Get an int constant identifying the type of element.
  166. * @see org.apache.xalan.templates.Constants
  167. *
  168. * @return The token ID for this element
  169. */
  170. public int getXSLToken()
  171. {
  172. return Constants.ELEMNAME_ELEMENT;
  173. }
  174. /**
  175. * Return the node name.
  176. *
  177. * @return This element's name
  178. */
  179. public String getNodeName()
  180. {
  181. return Constants.ELEMNAME_ELEMENT_STRING;
  182. }
  183. /**
  184. * Validate that the node name is good.
  185. *
  186. * @param nodeName Name of the node being constructed, which may be null.
  187. *
  188. * @return true if the node name is valid, false otherwise.
  189. */
  190. protected boolean validateNodeName(String nodeName)
  191. {
  192. if(nodeName == null)
  193. return false;
  194. int len = nodeName.length();
  195. if(len == 0)
  196. return false;
  197. int indexOfNSSep = nodeName.indexOf(':');
  198. if(indexOfNSSep + 1 == len)
  199. return false;
  200. if(indexOfNSSep == 0)
  201. return false;
  202. String localName = QName.getLocalPart(nodeName);
  203. if(isValidNCName(localName))
  204. {
  205. String prefix = QName.getPrefixPart(nodeName);
  206. if(prefix.length() == 0)
  207. return true;
  208. if(isValidNCName(prefix))
  209. return true;
  210. }
  211. return false;
  212. }
  213. /**
  214. * Resolve the namespace into a prefix. Meant to be
  215. * overidded by elemAttribute if this class is derived.
  216. *
  217. * @param rhandler The current result tree handler.
  218. * @param prefix The probable prefix if already known.
  219. * @param nodeNamespace The namespace.
  220. *
  221. * @return The prefix to be used.
  222. */
  223. protected String resolvePrefix(ResultTreeHandler rhandler,
  224. String prefix, String nodeNamespace)
  225. throws TransformerException
  226. {
  227. // if (null != prefix && prefix.length() == 0)
  228. // {
  229. // String foundPrefix = rhandler.getPrefix(nodeNamespace);
  230. //
  231. // // System.out.println("nsPrefix: "+nsPrefix);
  232. // if (null == foundPrefix)
  233. // foundPrefix = "";
  234. // }
  235. return prefix;
  236. }
  237. /**
  238. * Create an element in the result tree.
  239. * The xsl:element element allows an element to be created with a
  240. * computed name. The expanded-name of the element to be created
  241. * is specified by a required name attribute and an optional namespace
  242. * attribute. The content of the xsl:element element is a template
  243. * for the attributes and children of the created element.
  244. *
  245. * @param transformer non-null reference to the the current transform-time state.
  246. *
  247. * @throws TransformerException
  248. */
  249. public void execute(
  250. TransformerImpl transformer)
  251. throws TransformerException
  252. {
  253. if (TransformerImpl.S_DEBUG)
  254. transformer.getTraceManager().fireTraceEvent(this);
  255. ResultTreeHandler rhandler = transformer.getResultTreeHandler();
  256. XPathContext xctxt = transformer.getXPathContext();
  257. int sourceNode = xctxt.getCurrentNode();
  258. String nodeName = m_name_avt == null ? null : m_name_avt.evaluate(xctxt, sourceNode, this);
  259. String prefix = null;
  260. String nodeNamespace = "";
  261. // Only validate if an AVT was used.
  262. if ((nodeName != null) && (!m_name_avt.isSimple()) && (!validateNodeName(nodeName)))
  263. {
  264. transformer.getMsgMgr().warn(
  265. this, XSLTErrorResources.WG_ILLEGAL_ATTRIBUTE_VALUE,
  266. new Object[]{ Constants.ATTRNAME_NAME, nodeName });
  267. nodeName = null;
  268. }
  269. else if (nodeName != null)
  270. {
  271. prefix = QName.getPrefixPart(nodeName);
  272. if (null != m_namespace_avt)
  273. {
  274. nodeNamespace = m_namespace_avt.evaluate(xctxt, sourceNode, this);
  275. if (null == nodeNamespace ||
  276. (prefix != null && prefix.length()>0 && nodeNamespace.length()== 0) )
  277. transformer.getMsgMgr().error(
  278. this, XSLTErrorResources.ER_NULL_URI_NAMESPACE);
  279. else
  280. {
  281. // Determine the actual prefix that we will use for this nodeNamespace
  282. prefix = resolvePrefix(rhandler, prefix, nodeNamespace);
  283. if (null == prefix)
  284. prefix = "";
  285. if (prefix.length() > 0)
  286. nodeName = (prefix + ":" + QName.getLocalPart(nodeName));
  287. else
  288. nodeName = QName.getLocalPart(nodeName);
  289. }
  290. }
  291. // No namespace attribute was supplied. Use the namespace declarations
  292. // currently in effect for the xsl:element element.
  293. else
  294. {
  295. try
  296. {
  297. // Maybe temporary, until I get this worked out. test: axes59
  298. nodeNamespace = getNamespaceForPrefix(prefix);
  299. // If we get back a null nodeNamespace, that means that this prefix could
  300. // not be found in the table. This is okay only for a default namespace
  301. // that has never been declared.
  302. if ( (null == nodeNamespace) && (prefix.length() == 0) )
  303. nodeNamespace = "";
  304. else if (null == nodeNamespace)
  305. {
  306. transformer.getMsgMgr().warn(
  307. this, XSLTErrorResources.WG_COULD_NOT_RESOLVE_PREFIX,
  308. new Object[]{ prefix });
  309. nodeName = null;
  310. }
  311. }
  312. catch (Exception ex)
  313. {
  314. transformer.getMsgMgr().warn(
  315. this, XSLTErrorResources.WG_COULD_NOT_RESOLVE_PREFIX,
  316. new Object[]{ prefix });
  317. nodeName = null;
  318. }
  319. }
  320. }
  321. constructNode(nodeName, prefix, nodeNamespace, transformer);
  322. if (TransformerImpl.S_DEBUG)
  323. transformer.getTraceManager().fireTraceEndEvent(this);
  324. }
  325. /**
  326. * Construct a node in the result tree. This method is overloaded by
  327. * xsl:attribute. At this class level, this method creates an element.
  328. * If the node is null, we instantiate only the content of the node in accordance
  329. * with section 7.1.2 of the XSLT 1.0 Recommendation.
  330. *
  331. * @param nodeName The name of the node, which may be <code>null</code>. If <code>null</code>,
  332. * only the non-attribute children of this node will be processed.
  333. * @param prefix The prefix for the namespace, which may be <code>null</code>.
  334. * If not <code>null</code>, this prefix will be mapped and unmapped.
  335. * @param nodeNamespace The namespace of the node, which may be not be <code>null</code>.
  336. * @param transformer non-null reference to the the current transform-time state.
  337. *
  338. * @throws TransformerException
  339. */
  340. void constructNode(
  341. String nodeName, String prefix, String nodeNamespace, TransformerImpl transformer)
  342. throws TransformerException
  343. {
  344. boolean shouldAddAttrs;
  345. try
  346. {
  347. ResultTreeHandler rhandler = transformer.getResultTreeHandler();
  348. if (null == nodeName)
  349. {
  350. shouldAddAttrs = false;
  351. }
  352. else
  353. {
  354. // Add namespace declarations.
  355. executeNSDecls(transformer);
  356. if (null != prefix)
  357. {
  358. rhandler.startPrefixMapping(prefix, nodeNamespace, true);
  359. }
  360. rhandler.startElement(nodeNamespace, QName.getLocalPart(nodeName),
  361. nodeName, null);
  362. super.execute(transformer);
  363. shouldAddAttrs = true;
  364. }
  365. transformer.executeChildTemplates(this, shouldAddAttrs);
  366. // Now end the element if name was valid
  367. if (null != nodeName)
  368. {
  369. rhandler.endElement(nodeNamespace, QName.getLocalPart(nodeName),
  370. nodeName);
  371. if (null != prefix)
  372. {
  373. rhandler.endPrefixMapping(prefix);
  374. }
  375. unexecuteNSDecls(transformer);
  376. }
  377. }
  378. catch (SAXException se)
  379. {
  380. throw new TransformerException(se);
  381. }
  382. }
  383. /**
  384. * Call the children visitors.
  385. * @param visitor The visitor whose appropriate method will be called.
  386. */
  387. protected void callChildVisitors(XSLTVisitor visitor, boolean callAttrs)
  388. {
  389. if(callAttrs)
  390. {
  391. if(null != m_name_avt)
  392. m_name_avt.callVisitors(visitor);
  393. if(null != m_namespace_avt)
  394. m_namespace_avt.callVisitors(visitor);
  395. }
  396. super.callChildVisitors(visitor, callAttrs);
  397. }
  398. }