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: ElemAttribute.java 469304 2006-10-30 22:29:47Z 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.NamespaceMappings;
28import org.apache.xml.serializer.SerializationHandler;
29import org.apache.xml.utils.QName;
30import org.apache.xml.utils.XML11Char;
31
32import org.xml.sax.SAXException;
33
34/**
35 * Implement xsl:attribute.
36 * <pre>
37 * &amp;!ELEMENT xsl:attribute %char-template;>
38 * &amp;!ATTLIST xsl:attribute
39 *   name %avt; #REQUIRED
40 *   namespace %avt; #IMPLIED
41 *   %space-att;
42 * &amp;
43 * </pre>
44 * @see <a href="http://www.w3.org/TR/xslt#creating-attributes">creating-attributes in XSLT Specification</a>
45 * @xsl.usage advanced
46 */
47public class ElemAttribute extends ElemElement
48{
49    static final long serialVersionUID = 8817220961566919187L;
50
51  /**
52   * Get an int constant identifying the type of element.
53   * @see org.apache.xalan.templates.Constants
54   *
55   * @return The token ID for this element
56   */
57  public int getXSLToken()
58  {
59    return Constants.ELEMNAME_ATTRIBUTE;
60  }
61
62  /**
63   * Return the node name.
64   *
65   * @return The element name
66   */
67  public String getNodeName()
68  {
69    return Constants.ELEMNAME_ATTRIBUTE_STRING;
70  }
71
72  /**
73   * Create an attribute in the result tree.
74   * @see <a href="http://www.w3.org/TR/xslt#creating-attributes">creating-attributes in XSLT Specification</a>
75   *
76   * @param transformer non-null reference to the the current transform-time state.
77   *
78   * @throws TransformerException
79   */
80//  public void execute(
81//          TransformerImpl transformer)
82//            throws TransformerException
83//  {
84    //SerializationHandler rhandler = transformer.getSerializationHandler();
85
86    // If they are trying to add an attribute when there isn't an
87    // element pending, it is an error.
88    // I don't think we need this check here because it is checked in
89    // ResultTreeHandler.addAttribute.  (is)
90//    if (!rhandler.isElementPending())
91//    {
92//      // Make sure the trace event is sent.
93//      if (TransformerImpl.S_DEBUG)
94//        transformer.getTraceManager().fireTraceEvent(this);
95//
96//      XPathContext xctxt = transformer.getXPathContext();
97//      int sourceNode = xctxt.getCurrentNode();
98//      String attrName = m_name_avt.evaluate(xctxt, sourceNode, this);
99//      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}
277