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    }