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