1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the  "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *     http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18/*
19 * $Id: ElemElement.java 468643 2006-10-28 06:56:03Z minchau $
20 */
21package org.apache.xalan.templates;
22
23import javax.xml.transform.TransformerException;
24
25import org.apache.xalan.res.XSLTErrorResources;
26import org.apache.xalan.transformer.TransformerImpl;
27import org.apache.xml.serializer.SerializationHandler;
28import org.apache.xml.utils.QName;
29import org.apache.xml.utils.XML11Char;
30import org.apache.xpath.XPathContext;
31import org.xml.sax.SAXException;
32
33/**
34 * Implement xsl:element
35 * <pre>
36 * <!ELEMENT xsl:element %template;>
37 * <!ATTLIST xsl:element
38 *   name %avt; #REQUIRED
39 *   namespace %avt; #IMPLIED
40 *   use-attribute-sets %qnames; #IMPLIED
41 *   %space-att;
42 * >
43 * </pre>
44 * @see <a href="http://www.w3.org/TR/xslt#section-Creating-Elements-with-xsl:element">XXX in XSLT Specification</a>
45 * @xsl.usage advanced
46 */
47public class ElemElement extends ElemUse
48{
49    static final long serialVersionUID = -324619535592435183L;
50
51  /**
52   * The name attribute is interpreted as an attribute value template.
53   * It is an error if the string that results from instantiating the
54   * attribute value template is not a QName.
55   * @serial
56   */
57  protected AVT m_name_avt = null;
58
59  /**
60   * Set the "name" attribute.
61   * The name attribute is interpreted as an attribute value template.
62   * It is an error if the string that results from instantiating the
63   * attribute value template is not a QName.
64   *
65   * @param v Name attribute to set for this element
66   */
67  public void setName(AVT v)
68  {
69    m_name_avt = v;
70  }
71
72  /**
73   * Get the "name" attribute.
74   * The name attribute is interpreted as an attribute value template.
75   * It is an error if the string that results from instantiating the
76   * attribute value template is not a QName.
77   *
78   * @return Name attribute for this element
79   */
80  public AVT getName()
81  {
82    return m_name_avt;
83  }
84
85  /**
86   * If the namespace attribute is present, then it also is interpreted
87   * as an attribute value template. The string that results from
88   * instantiating the attribute value template should be a URI reference.
89   * It is not an error if the string is not a syntactically legal URI reference.
90   * @serial
91   */
92  protected AVT m_namespace_avt = null;
93
94  /**
95   * Set the "namespace" attribute.
96   * If the namespace attribute is present, then it also is interpreted
97   * as an attribute value template. The string that results from
98   * instantiating the attribute value template should be a URI reference.
99   * 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 	SerializationHandler rhandler = transformer.getSerializationHandler();
206    XPathContext xctxt = transformer.getXPathContext();
207    int sourceNode = xctxt.getCurrentNode();
208
209
210    String nodeName = m_name_avt == null ? null : m_name_avt.evaluate(xctxt, sourceNode, this);
211
212    String prefix = null;
213    String nodeNamespace = "";
214
215    // Only validate if an AVT was used.
216    if ((nodeName != null) && (!m_name_avt.isSimple()) && (!XML11Char.isXML11ValidQName(nodeName)))
217    {
218      transformer.getMsgMgr().warn(
219        this, XSLTErrorResources.WG_ILLEGAL_ATTRIBUTE_VALUE,
220        new Object[]{ Constants.ATTRNAME_NAME, nodeName });
221
222      nodeName = null;
223    }
224
225    else if (nodeName != null)
226    {
227      prefix = QName.getPrefixPart(nodeName);
228
229      if (null != m_namespace_avt)
230      {
231        nodeNamespace = m_namespace_avt.evaluate(xctxt, sourceNode, this);
232        if (null == nodeNamespace ||
233            (prefix != null && prefix.length()>0 && nodeNamespace.length()== 0) )
234          transformer.getMsgMgr().error(
235              this, XSLTErrorResources.ER_NULL_URI_NAMESPACE);
236        else
237        {
238        // Determine the actual prefix that we will use for this nodeNamespace
239
240        prefix = resolvePrefix(rhandler, prefix, nodeNamespace);
241        if (null == prefix)
242          prefix = "";
243
244        if (prefix.length() > 0)
245          nodeName = (prefix + ":" + QName.getLocalPart(nodeName));
246        else
247          nodeName = QName.getLocalPart(nodeName);
248        }
249      }
250
251      // No namespace attribute was supplied. Use the namespace declarations
252      // currently in effect for the xsl:element element.
253      else
254      {
255        try
256        {
257          // Maybe temporary, until I get this worked out.  test: axes59
258          nodeNamespace = getNamespaceForPrefix(prefix);
259
260          // If we get back a null nodeNamespace, that means that this prefix could
261          // not be found in the table.  This is okay only for a default namespace
262          // that has never been declared.
263
264          if ( (null == nodeNamespace) && (prefix.length() == 0) )
265            nodeNamespace = "";
266          else if (null == nodeNamespace)
267          {
268            transformer.getMsgMgr().warn(
269              this, XSLTErrorResources.WG_COULD_NOT_RESOLVE_PREFIX,
270              new Object[]{ prefix });
271
272            nodeName = null;
273          }
274
275        }
276        catch (Exception ex)
277        {
278          transformer.getMsgMgr().warn(
279            this, XSLTErrorResources.WG_COULD_NOT_RESOLVE_PREFIX,
280            new Object[]{ prefix });
281
282          nodeName = null;
283        }
284      }
285    }
286
287    constructNode(nodeName, prefix, nodeNamespace, transformer);
288  }
289
290  /**
291   * Construct a node in the result tree.  This method is overloaded by
292   * xsl:attribute. At this class level, this method creates an element.
293   * If the node is null, we instantiate only the content of the node in accordance
294   * with section 7.1.2 of the XSLT 1.0 Recommendation.
295   *
296   * @param nodeName The name of the node, which may be <code>null</code>.  If <code>null</code>,
297   *                 only the non-attribute children of this node will be processed.
298   * @param prefix The prefix for the namespace, which may be <code>null</code>.
299   *               If not <code>null</code>, this prefix will be mapped and unmapped.
300   * @param nodeNamespace The namespace of the node, which may be not be <code>null</code>.
301   * @param transformer non-null reference to the the current transform-time state.
302   *
303   * @throws TransformerException
304   */
305  void constructNode(
306          String nodeName, String prefix, String nodeNamespace, TransformerImpl transformer)
307            throws TransformerException
308  {
309
310    boolean shouldAddAttrs;
311
312    try
313    {
314      SerializationHandler rhandler = transformer.getResultTreeHandler();
315
316      if (null == nodeName)
317      {
318        shouldAddAttrs = false;
319      }
320      else
321      {
322        if (null != prefix)
323        {
324          rhandler.startPrefixMapping(prefix, nodeNamespace, true);
325        }
326
327        rhandler.startElement(nodeNamespace, QName.getLocalPart(nodeName),
328                              nodeName);
329
330        super.execute(transformer);
331
332        shouldAddAttrs = true;
333      }
334
335      transformer.executeChildTemplates(this, shouldAddAttrs);
336
337      // Now end the element if name was valid
338      if (null != nodeName)
339      {
340        rhandler.endElement(nodeNamespace, QName.getLocalPart(nodeName),
341                            nodeName);
342        if (null != prefix)
343        {
344          rhandler.endPrefixMapping(prefix);
345        }
346      }
347    }
348    catch (SAXException se)
349    {
350      throw new TransformerException(se);
351    }
352  }
353
354  /**
355   * Call the children visitors.
356   * @param visitor The visitor whose appropriate method will be called.
357   */
358  protected void callChildVisitors(XSLTVisitor visitor, boolean callAttrs)
359  {
360  	if(callAttrs)
361  	{
362  	  if(null != m_name_avt)
363  		m_name_avt.callVisitors(visitor);
364
365  	  if(null != m_namespace_avt)
366  		m_namespace_avt.callVisitors(visitor);
367  	}
368
369    super.callChildVisitors(visitor, callAttrs);
370  }
371
372}
373