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: ElemCopyOf.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.xalan.transformer.TreeWalker2Result; 28 import org.apache.xml.dtm.DTM; 29 import org.apache.xml.dtm.DTMIterator; 30 import org.apache.xml.dtm.ref.DTMTreeWalker; 31 import org.apache.xalan.serialize.SerializerUtils; 32 import org.apache.xml.serializer.SerializationHandler; 33 import org.apache.xpath.XPath; 34 import org.apache.xpath.XPathContext; 35 import org.apache.xpath.objects.XObject; 36 37 /** 38 * Implement xsl:copy-of. 39 * <pre> 40 * <!ELEMENT xsl:copy-of EMPTY> 41 * <!ATTLIST xsl:copy-of select %expr; #REQUIRED> 42 * </pre> 43 * @see <a href="http://www.w3.org/TR/xslt#copy-of">copy-of in XSLT Specification</a> 44 * @xsl.usage advanced 45 */ 46 public class ElemCopyOf extends ElemTemplateElement 47 { 48 static final long serialVersionUID = -7433828829497411127L; 49 50 /** 51 * The required select attribute contains an expression. 52 * @serial 53 */ 54 public XPath m_selectExpression = null; 55 56 /** 57 * Set the "select" attribute. 58 * The required select attribute contains an expression. 59 * 60 * @param expr Expression for select attribute 61 */ 62 public void setSelect(XPath expr) 63 { 64 m_selectExpression = expr; 65 } 66 67 /** 68 * Get the "select" attribute. 69 * The required select attribute contains an expression. 70 * 71 * @return Expression for select attribute 72 */ 73 public XPath getSelect() 74 { 75 return m_selectExpression; 76 } 77 78 /** 79 * This function is called after everything else has been 80 * recomposed, and allows the template to set remaining 81 * values that may be based on some other property that 82 * depends on recomposition. 83 */ 84 public void compose(StylesheetRoot sroot) throws TransformerException 85 { 86 super.compose(sroot); 87 88 StylesheetRoot.ComposeState cstate = sroot.getComposeState(); 89 m_selectExpression.fixupVariables(cstate.getVariableNames(), cstate.getGlobalsSize()); 90 } 91 92 /** 93 * Get an int constant identifying the type of element. 94 * @see org.apache.xalan.templates.Constants 95 * 96 * @return The token ID for this element 97 */ 98 public int getXSLToken() 99 { 100 return Constants.ELEMNAME_COPY_OF; 101 } 102 103 /** 104 * Return the node name. 105 * 106 * @return The element's name 107 */ 108 public String getNodeName() 109 { 110 return Constants.ELEMNAME_COPY_OF_STRING; 111 } 112 113 /** 114 * The xsl:copy-of element can be used to insert a result tree 115 * fragment into the result tree, without first converting it to 116 * a string as xsl:value-of does (see [7.6.1 Generating Text with 117 * xsl:value-of]). 118 * 119 * @param transformer non-null reference to the the current transform-time state. 120 * 121 * @throws TransformerException 122 */ 123 public void execute( 124 TransformerImpl transformer) 125 throws TransformerException 126 { 127 try 128 { 129 XPathContext xctxt = transformer.getXPathContext(); 130 int sourceNode = xctxt.getCurrentNode(); 131 XObject value = m_selectExpression.execute(xctxt, sourceNode, this); 132 133 SerializationHandler handler = transformer.getSerializationHandler(); 134 135 if (null != value) 136 { 137 int type = value.getType(); 138 String s; 139 140 switch (type) 141 { 142 case XObject.CLASS_BOOLEAN : 143 case XObject.CLASS_NUMBER : 144 case XObject.CLASS_STRING : 145 s = value.str(); 146 147 handler.characters(s.toCharArray(), 0, s.length()); 148 break; 149 case XObject.CLASS_NODESET : 150 151 // System.out.println(value); 152 DTMIterator nl = value.iter(); 153 154 // Copy the tree. 155 DTMTreeWalker tw = new TreeWalker2Result(transformer, handler); 156 int pos; 157 158 while (DTM.NULL != (pos = nl.nextNode())) 159 { 160 DTM dtm = xctxt.getDTMManager().getDTM(pos); 161 short t = dtm.getNodeType(pos); 162 163 // If we just copy the whole document, a startDoc and endDoc get 164 // generated, so we need to only walk the child nodes. 165 if (t == DTM.DOCUMENT_NODE) 166 { 167 for (int child = dtm.getFirstChild(pos); child != DTM.NULL; 168 child = dtm.getNextSibling(child)) 169 { 170 tw.traverse(child); 171 } 172 } 173 else if (t == DTM.ATTRIBUTE_NODE) 174 { 175 SerializerUtils.addAttribute(handler, pos); 176 } 177 else 178 { 179 tw.traverse(pos); 180 } 181 } 182 // nl.detach(); 183 break; 184 case XObject.CLASS_RTREEFRAG : 185 SerializerUtils.outputResultTreeFragment( 186 handler, value, transformer.getXPathContext()); 187 break; 188 default : 189 190 s = value.str(); 191 192 handler.characters(s.toCharArray(), 0, s.length()); 193 break; 194 } 195 } 196 197 // I don't think we want this. -sb 198 // if (transformer.getDebug()) 199 // transformer.getTraceManager().fireSelectedEvent(sourceNode, this, 200 // "endSelect", m_selectExpression, value); 201 202 } 203 catch(org.xml.sax.SAXException se) 204 { 205 throw new TransformerException(se); 206 } 207 208 } 209 210 /** 211 * Add a child to the child list. 212 * 213 * @param newChild Child to add to this node's child list 214 * 215 * @return Child just added to child list 216 */ 217 public ElemTemplateElement appendChild(ElemTemplateElement newChild) 218 { 219 220 error(XSLTErrorResources.ER_CANNOT_ADD, 221 new Object[]{ newChild.getNodeName(), 222 this.getNodeName() }); //"Can not add " +((ElemTemplateElement)newChild).m_elemName + 223 224 //" to " + this.m_elemName); 225 return null; 226 } 227 228 /** 229 * Call the children visitors. 230 * @param visitor The visitor whose appropriate method will be called. 231 */ 232 protected void callChildVisitors(XSLTVisitor visitor, boolean callAttrs) 233 { 234 if(callAttrs) 235 m_selectExpression.getExpression().callVisitors(m_selectExpression, visitor); 236 super.callChildVisitors(visitor, callAttrs); 237 } 238 239 } 240