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: ElemElement.java 468643 2006-10-28 06:56:03Z minchau $
020 */
021 package org.apache.xalan.templates;
022
023 import javax.xml.transform.TransformerException;
024
025 import org.apache.xalan.res.XSLTErrorResources;
026 import org.apache.xalan.transformer.TransformerImpl;
027 import org.apache.xml.serializer.SerializationHandler;
028 import org.apache.xml.utils.QName;
029 import org.apache.xml.utils.XML11Char;
030 import org.apache.xpath.XPathContext;
031 import org.xml.sax.SAXException;
032
033 /**
034 * Implement xsl:element
035 * <pre>
036 * <!ELEMENT xsl:element %template;>
037 * <!ATTLIST xsl:element
038 * name %avt; #REQUIRED
039 * namespace %avt; #IMPLIED
040 * use-attribute-sets %qnames; #IMPLIED
041 * %space-att;
042 * >
043 * </pre>
044 * @see <a href="http://www.w3.org/TR/xslt#section-Creating-Elements-with-xsl:element">XXX in XSLT Specification</a>
045 * @xsl.usage advanced
046 */
047 public class ElemElement extends ElemUse
048 {
049 static final long serialVersionUID = -324619535592435183L;
050
051 /**
052 * The name attribute is interpreted as an attribute value template.
053 * It is an error if the string that results from instantiating the
054 * attribute value template is not a QName.
055 * @serial
056 */
057 protected AVT m_name_avt = null;
058
059 /**
060 * Set the "name" attribute.
061 * The name attribute is interpreted as an attribute value template.
062 * It is an error if the string that results from instantiating the
063 * attribute value template is not a QName.
064 *
065 * @param v Name attribute to set for this element
066 */
067 public void setName(AVT v)
068 {
069 m_name_avt = v;
070 }
071
072 /**
073 * Get the "name" attribute.
074 * The name attribute is interpreted as an attribute value template.
075 * It is an error if the string that results from instantiating the
076 * attribute value template is not a QName.
077 *
078 * @return Name attribute for this element
079 */
080 public AVT getName()
081 {
082 return m_name_avt;
083 }
084
085 /**
086 * If the namespace attribute is present, then it also is interpreted
087 * as an attribute value template. The string that results from
088 * instantiating the attribute value template should be a URI reference.
089 * It is not an error if the string is not a syntactically legal URI reference.
090 * @serial
091 */
092 protected AVT m_namespace_avt = null;
093
094 /**
095 * Set the "namespace" attribute.
096 * If the namespace attribute is present, then it also is interpreted
097 * as an attribute value template. The string that results from
098 * instantiating the attribute value template should be a URI reference.
099 * It is not an error if the string is not a syntactically legal URI reference.
100 *
101 * @param v NameSpace attribute to set for this element
102 */
103 public void setNamespace(AVT v)
104 {
105 m_namespace_avt = v;
106 }
107
108 /**
109 * Get the "namespace" attribute.
110 * If the namespace attribute is present, then it also is interpreted
111 * as an attribute value template. The string that results from
112 * instantiating the attribute value template should be a URI reference.
113 * It is not an error if the string is not a syntactically legal URI reference.
114 *
115 * @return Namespace attribute for this element
116 */
117 public AVT getNamespace()
118 {
119 return m_namespace_avt;
120 }
121
122 /**
123 * This function is called after everything else has been
124 * recomposed, and allows the template to set remaining
125 * values that may be based on some other property that
126 * depends on recomposition.
127 */
128 public void compose(StylesheetRoot sroot) throws TransformerException
129 {
130 super.compose(sroot);
131
132 StylesheetRoot.ComposeState cstate = sroot.getComposeState();
133 java.util.Vector vnames = cstate.getVariableNames();
134 if(null != m_name_avt)
135 m_name_avt.fixupVariables(vnames, cstate.getGlobalsSize());
136 if(null != m_namespace_avt)
137 m_namespace_avt.fixupVariables(vnames, cstate.getGlobalsSize());
138 }
139
140
141 /**
142 * Get an int constant identifying the type of element.
143 * @see org.apache.xalan.templates.Constants
144 *
145 * @return The token ID for this element
146 */
147 public int getXSLToken()
148 {
149 return Constants.ELEMNAME_ELEMENT;
150 }
151
152 /**
153 * Return the node name.
154 *
155 * @return This element's name
156 */
157 public String getNodeName()
158 {
159 return Constants.ELEMNAME_ELEMENT_STRING;
160 }
161
162 /**
163 * Resolve the namespace into a prefix. Meant to be
164 * overidded by elemAttribute if this class is derived.
165 *
166 * @param rhandler The current result tree handler.
167 * @param prefix The probable prefix if already known.
168 * @param nodeNamespace The namespace.
169 *
170 * @return The prefix to be used.
171 */
172 protected String resolvePrefix(SerializationHandler rhandler,
173 String prefix, String nodeNamespace)
174 throws TransformerException
175 {
176
177 // if (null != prefix && prefix.length() == 0)
178 // {
179 // String foundPrefix = rhandler.getPrefix(nodeNamespace);
180 //
181 // // System.out.println("nsPrefix: "+nsPrefix);
182 // if (null == foundPrefix)
183 // foundPrefix = "";
184 // }
185 return prefix;
186 }
187
188 /**
189 * Create an element in the result tree.
190 * The xsl:element element allows an element to be created with a
191 * computed name. The expanded-name of the element to be created
192 * is specified by a required name attribute and an optional namespace
193 * attribute. The content of the xsl:element element is a template
194 * for the attributes and children of the created element.
195 *
196 * @param transformer non-null reference to the the current transform-time state.
197 *
198 * @throws TransformerException
199 */
200 public void execute(
201 TransformerImpl transformer)
202 throws TransformerException
203 {
204
205 if (transformer.getDebug())
206 transformer.getTraceManager().fireTraceEvent(this);
207
208 SerializationHandler rhandler = transformer.getSerializationHandler();
209 XPathContext xctxt = transformer.getXPathContext();
210 int sourceNode = xctxt.getCurrentNode();
211
212
213 String nodeName = m_name_avt == null ? null : m_name_avt.evaluate(xctxt, sourceNode, this);
214
215 String prefix = null;
216 String nodeNamespace = "";
217
218 // Only validate if an AVT was used.
219 if ((nodeName != null) && (!m_name_avt.isSimple()) && (!XML11Char.isXML11ValidQName(nodeName)))
220 {
221 transformer.getMsgMgr().warn(
222 this, XSLTErrorResources.WG_ILLEGAL_ATTRIBUTE_VALUE,
223 new Object[]{ Constants.ATTRNAME_NAME, nodeName });
224
225 nodeName = null;
226 }
227
228 else if (nodeName != null)
229 {
230 prefix = QName.getPrefixPart(nodeName);
231
232 if (null != m_namespace_avt)
233 {
234 nodeNamespace = m_namespace_avt.evaluate(xctxt, sourceNode, this);
235 if (null == nodeNamespace ||
236 (prefix != null && prefix.length()>0 && nodeNamespace.length()== 0) )
237 transformer.getMsgMgr().error(
238 this, XSLTErrorResources.ER_NULL_URI_NAMESPACE);
239 else
240 {
241 // Determine the actual prefix that we will use for this nodeNamespace
242
243 prefix = resolvePrefix(rhandler, prefix, nodeNamespace);
244 if (null == prefix)
245 prefix = "";
246
247 if (prefix.length() > 0)
248 nodeName = (prefix + ":" + QName.getLocalPart(nodeName));
249 else
250 nodeName = QName.getLocalPart(nodeName);
251 }
252 }
253
254 // No namespace attribute was supplied. Use the namespace declarations
255 // currently in effect for the xsl:element element.
256 else
257 {
258 try
259 {
260 // Maybe temporary, until I get this worked out. test: axes59
261 nodeNamespace = getNamespaceForPrefix(prefix);
262
263 // If we get back a null nodeNamespace, that means that this prefix could
264 // not be found in the table. This is okay only for a default namespace
265 // that has never been declared.
266
267 if ( (null == nodeNamespace) && (prefix.length() == 0) )
268 nodeNamespace = "";
269 else if (null == nodeNamespace)
270 {
271 transformer.getMsgMgr().warn(
272 this, XSLTErrorResources.WG_COULD_NOT_RESOLVE_PREFIX,
273 new Object[]{ prefix });
274
275 nodeName = null;
276 }
277
278 }
279 catch (Exception ex)
280 {
281 transformer.getMsgMgr().warn(
282 this, XSLTErrorResources.WG_COULD_NOT_RESOLVE_PREFIX,
283 new Object[]{ prefix });
284
285 nodeName = null;
286 }
287 }
288 }
289
290 constructNode(nodeName, prefix, nodeNamespace, transformer);
291
292 if (transformer.getDebug())
293 transformer.getTraceManager().fireTraceEndEvent(this);
294 }
295
296 /**
297 * Construct a node in the result tree. This method is overloaded by
298 * xsl:attribute. At this class level, this method creates an element.
299 * If the node is null, we instantiate only the content of the node in accordance
300 * with section 7.1.2 of the XSLT 1.0 Recommendation.
301 *
302 * @param nodeName The name of the node, which may be <code>null</code>. If <code>null</code>,
303 * only the non-attribute children of this node will be processed.
304 * @param prefix The prefix for the namespace, which may be <code>null</code>.
305 * If not <code>null</code>, this prefix will be mapped and unmapped.
306 * @param nodeNamespace The namespace of the node, which may be not be <code>null</code>.
307 * @param transformer non-null reference to the the current transform-time state.
308 *
309 * @throws TransformerException
310 */
311 void constructNode(
312 String nodeName, String prefix, String nodeNamespace, TransformerImpl transformer)
313 throws TransformerException
314 {
315
316 boolean shouldAddAttrs;
317
318 try
319 {
320 SerializationHandler rhandler = transformer.getResultTreeHandler();
321
322 if (null == nodeName)
323 {
324 shouldAddAttrs = false;
325 }
326 else
327 {
328 if (null != prefix)
329 {
330 rhandler.startPrefixMapping(prefix, nodeNamespace, true);
331 }
332
333 rhandler.startElement(nodeNamespace, QName.getLocalPart(nodeName),
334 nodeName);
335
336 super.execute(transformer);
337
338 shouldAddAttrs = true;
339 }
340
341 transformer.executeChildTemplates(this, shouldAddAttrs);
342
343 // Now end the element if name was valid
344 if (null != nodeName)
345 {
346 rhandler.endElement(nodeNamespace, QName.getLocalPart(nodeName),
347 nodeName);
348 if (null != prefix)
349 {
350 rhandler.endPrefixMapping(prefix);
351 }
352 }
353 }
354 catch (SAXException se)
355 {
356 throw new TransformerException(se);
357 }
358 }
359
360 /**
361 * Call the children visitors.
362 * @param visitor The visitor whose appropriate method will be called.
363 */
364 protected void callChildVisitors(XSLTVisitor visitor, boolean callAttrs)
365 {
366 if(callAttrs)
367 {
368 if(null != m_name_avt)
369 m_name_avt.callVisitors(visitor);
370
371 if(null != m_namespace_avt)
372 m_namespace_avt.callVisitors(visitor);
373 }
374
375 super.callChildVisitors(visitor, callAttrs);
376 }
377
378 }