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: ElemAttribute.java 469304 2006-10-30 22:29:47Z 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.NamespaceMappings;
028    import org.apache.xml.serializer.SerializationHandler;
029    import org.apache.xml.utils.QName;
030    import org.apache.xml.utils.XML11Char;
031    
032    import org.xml.sax.SAXException;
033    
034    /**
035     * Implement xsl:attribute.
036     * <pre>
037     * &amp;!ELEMENT xsl:attribute %char-template;>
038     * &amp;!ATTLIST xsl:attribute
039     *   name %avt; #REQUIRED
040     *   namespace %avt; #IMPLIED
041     *   %space-att;
042     * &amp;
043     * </pre>
044     * @see <a href="http://www.w3.org/TR/xslt#creating-attributes">creating-attributes in XSLT Specification</a>
045     * @xsl.usage advanced
046     */
047    public class ElemAttribute extends ElemElement
048    {
049        static final long serialVersionUID = 8817220961566919187L;
050    
051      /**
052       * Get an int constant identifying the type of element.
053       * @see org.apache.xalan.templates.Constants
054       *
055       * @return The token ID for this element
056       */
057      public int getXSLToken()
058      {
059        return Constants.ELEMNAME_ATTRIBUTE;
060      }
061    
062      /**
063       * Return the node name.
064       *
065       * @return The element name 
066       */
067      public String getNodeName()
068      {
069        return Constants.ELEMNAME_ATTRIBUTE_STRING;
070      }
071    
072      /**
073       * Create an attribute in the result tree.
074       * @see <a href="http://www.w3.org/TR/xslt#creating-attributes">creating-attributes in XSLT Specification</a>
075       *
076       * @param transformer non-null reference to the the current transform-time state.
077       *
078       * @throws TransformerException
079       */
080    //  public void execute(
081    //          TransformerImpl transformer)
082    //            throws TransformerException
083    //  {
084        //SerializationHandler rhandler = transformer.getSerializationHandler();
085    
086        // If they are trying to add an attribute when there isn't an 
087        // element pending, it is an error.
088        // I don't think we need this check here because it is checked in 
089        // ResultTreeHandler.addAttribute.  (is)
090    //    if (!rhandler.isElementPending())
091    //    {
092    //      // Make sure the trace event is sent.
093    //      if (TransformerImpl.S_DEBUG)
094    //        transformer.getTraceManager().fireTraceEvent(this);
095    //
096    //      XPathContext xctxt = transformer.getXPathContext();
097    //      int sourceNode = xctxt.getCurrentNode();
098    //      String attrName = m_name_avt.evaluate(xctxt, sourceNode, this);
099    //      transformer.getMsgMgr().warn(this,
100    //                                   XSLTErrorResources.WG_ILLEGAL_ATTRIBUTE_POSITION,
101    //                                   new Object[]{ attrName });
102    //
103    //      if (TransformerImpl.S_DEBUG)
104    //        transformer.getTraceManager().fireTraceEndEvent(this);
105    //      return;
106    //
107    //      // warn(templateChild, sourceNode, "Trying to add attribute after element child has been added, ignoring...");
108    //    }
109        
110    //    super.execute(transformer);
111        
112    //  }
113      
114      /**
115       * Resolve the namespace into a prefix.  At this level, if no prefix exists, 
116       * then return a manufactured prefix.
117       *
118       * @param rhandler The current result tree handler.
119       * @param prefix The probable prefix if already known.
120       * @param nodeNamespace  The namespace, which should not be null.
121       *
122       * @return The prefix to be used.
123       */
124      protected String resolvePrefix(SerializationHandler rhandler,
125                                     String prefix, String nodeNamespace)
126        throws TransformerException
127      {
128    
129        if (null != prefix && (prefix.length() == 0 || prefix.equals("xmlns")))
130        {
131          // Since we can't use default namespace, in this case we try and 
132          // see if a prefix has already been defined or this namespace.
133          prefix = rhandler.getPrefix(nodeNamespace);
134    
135          // System.out.println("nsPrefix: "+nsPrefix);           
136          if (null == prefix || prefix.length() == 0 || prefix.equals("xmlns"))
137          {
138            if(nodeNamespace.length() > 0)
139            {
140                NamespaceMappings prefixMapping = rhandler.getNamespaceMappings();
141                prefix = prefixMapping.generateNextPrefix();
142            }
143            else
144              prefix = "";
145          }
146        }
147        return prefix;
148      }
149      
150      /**
151       * Validate that the node name is good.
152       * 
153       * @param nodeName Name of the node being constructed, which may be null.
154       * 
155       * @return true if the node name is valid, false otherwise.
156       */
157       protected boolean validateNodeName(String nodeName)
158       {
159          if(null == nodeName)
160            return false;
161          if(nodeName.equals("xmlns"))
162            return false;
163          return XML11Char.isXML11ValidQName(nodeName);
164       }
165      
166      /**
167       * Construct a node in the result tree.  This method is overloaded by 
168       * xsl:attribute. At this class level, this method creates an element.
169       *
170       * @param nodeName The name of the node, which may be null.
171       * @param prefix The prefix for the namespace, which may be null.
172       * @param nodeNamespace The namespace of the node, which may be null.
173       * @param transformer non-null reference to the the current transform-time state.
174       * @param sourceNode non-null reference to the <a href="http://www.w3.org/TR/xslt#dt-current-node">current source node</a>.
175       * @param mode reference, which may be null, to the <a href="http://www.w3.org/TR/xslt#modes">current mode</a>.
176       *
177       * @throws TransformerException
178       */
179      void constructNode(
180              String nodeName, String prefix, String nodeNamespace, TransformerImpl transformer)
181                throws TransformerException
182      {
183    
184        if(null != nodeName && nodeName.length() > 0)
185        {
186          SerializationHandler rhandler = transformer.getSerializationHandler();
187    
188          // Evaluate the value of this attribute
189          String val = transformer.transformToString(this);
190          try 
191          {
192            // Let the result tree handler add the attribute and its String value.
193            String localName = QName.getLocalPart(nodeName);
194            if(prefix != null && prefix.length() > 0){
195                rhandler.addAttribute(nodeNamespace, localName, nodeName, "CDATA", val, true);
196            }else{
197                rhandler.addAttribute("", localName, nodeName, "CDATA", val, true);
198            }
199          }
200          catch (SAXException e)
201          {
202          }
203        }
204      }
205    
206    
207      /**
208       * Add a child to the child list.
209       * <!ELEMENT xsl:attribute %char-template;>
210       * <!ATTLIST xsl:attribute
211       *   name %avt; #REQUIRED
212       *   namespace %avt; #IMPLIED
213       *   %space-att;
214       * >
215       *
216       * @param newChild Child to append to the list of this node's children
217       *
218       * @return The node we just appended to the children list 
219       *
220       * @throws DOMException
221       */
222      public ElemTemplateElement appendChild(ElemTemplateElement newChild)
223      {
224    
225        int type = ((ElemTemplateElement) newChild).getXSLToken();
226    
227        switch (type)
228        {
229    
230        // char-instructions 
231        case Constants.ELEMNAME_TEXTLITERALRESULT :
232        case Constants.ELEMNAME_APPLY_TEMPLATES :
233        case Constants.ELEMNAME_APPLY_IMPORTS :
234        case Constants.ELEMNAME_CALLTEMPLATE :
235        case Constants.ELEMNAME_FOREACH :
236        case Constants.ELEMNAME_VALUEOF :
237        case Constants.ELEMNAME_COPY_OF :
238        case Constants.ELEMNAME_NUMBER :
239        case Constants.ELEMNAME_CHOOSE :
240        case Constants.ELEMNAME_IF :
241        case Constants.ELEMNAME_TEXT :
242        case Constants.ELEMNAME_COPY :
243        case Constants.ELEMNAME_VARIABLE :
244        case Constants.ELEMNAME_MESSAGE :
245    
246          // instructions 
247          // case Constants.ELEMNAME_PI:
248          // case Constants.ELEMNAME_COMMENT:
249          // case Constants.ELEMNAME_ELEMENT:
250          // case Constants.ELEMNAME_ATTRIBUTE:
251          break;
252        default :
253          error(XSLTErrorResources.ER_CANNOT_ADD,
254                new Object[]{ newChild.getNodeName(),
255                              this.getNodeName() });  //"Can not add " +((ElemTemplateElement)newChild).m_elemName +
256    
257        //" to " + this.m_elemName);
258        }
259    
260        return super.appendChild(newChild);
261      }
262            /**
263             * @see ElemElement#setName(AVT)
264             */
265            public void setName(AVT v) {
266            if (v.isSimple())
267            {
268                if (v.getSimpleString().equals("xmlns"))
269                {
270                    throw new IllegalArgumentException();
271                }
272            }
273                    super.setName(v);
274            }
275    
276    }