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 }