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  */
21 package org.apache.xalan.templates;
22 
23 import javax.xml.transform.TransformerException;
24 
25 import org.apache.xalan.res.XSLTErrorResources;
26 import org.apache.xalan.transformer.TransformerImpl;
27 import org.apache.xml.serializer.SerializationHandler;
28 import org.apache.xml.utils.QName;
29 import org.apache.xml.utils.XML11Char;
30 import org.apache.xpath.XPathContext;
31 import 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  */
47 public 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    */
setName(AVT v)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    */
getName()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    */
setNamespace(AVT v)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    */
getNamespace()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    */
compose(StylesheetRoot sroot)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    */
getXSLToken()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    */
getNodeName()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    */
resolvePrefix(SerializationHandler rhandler, String prefix, String nodeNamespace)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    */
execute( TransformerImpl transformer)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    */
constructNode( String nodeName, String prefix, String nodeNamespace, TransformerImpl transformer)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    */
callChildVisitors(XSLTVisitor visitor, boolean callAttrs)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