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: ElemCopyOf.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.xalan.transformer.TreeWalker2Result; 028 import org.apache.xml.dtm.DTM; 029 import org.apache.xml.dtm.DTMIterator; 030 import org.apache.xml.dtm.ref.DTMTreeWalker; 031 import org.apache.xalan.serialize.SerializerUtils; 032 import org.apache.xml.serializer.SerializationHandler; 033 import org.apache.xpath.XPath; 034 import org.apache.xpath.XPathContext; 035 import org.apache.xpath.objects.XObject; 036 037 /** 038 * Implement xsl:copy-of. 039 * <pre> 040 * <!ELEMENT xsl:copy-of EMPTY> 041 * <!ATTLIST xsl:copy-of select %expr; #REQUIRED> 042 * </pre> 043 * @see <a href="http://www.w3.org/TR/xslt#copy-of">copy-of in XSLT Specification</a> 044 * @xsl.usage advanced 045 */ 046 public class ElemCopyOf extends ElemTemplateElement 047 { 048 static final long serialVersionUID = -7433828829497411127L; 049 050 /** 051 * The required select attribute contains an expression. 052 * @serial 053 */ 054 public XPath m_selectExpression = null; 055 056 /** 057 * Set the "select" attribute. 058 * The required select attribute contains an expression. 059 * 060 * @param expr Expression for select attribute 061 */ 062 public void setSelect(XPath expr) 063 { 064 m_selectExpression = expr; 065 } 066 067 /** 068 * Get the "select" attribute. 069 * The required select attribute contains an expression. 070 * 071 * @return Expression for select attribute 072 */ 073 public XPath getSelect() 074 { 075 return m_selectExpression; 076 } 077 078 /** 079 * This function is called after everything else has been 080 * recomposed, and allows the template to set remaining 081 * values that may be based on some other property that 082 * depends on recomposition. 083 */ 084 public void compose(StylesheetRoot sroot) throws TransformerException 085 { 086 super.compose(sroot); 087 088 StylesheetRoot.ComposeState cstate = sroot.getComposeState(); 089 m_selectExpression.fixupVariables(cstate.getVariableNames(), cstate.getGlobalsSize()); 090 } 091 092 /** 093 * Get an int constant identifying the type of element. 094 * @see org.apache.xalan.templates.Constants 095 * 096 * @return The token ID for this element 097 */ 098 public int getXSLToken() 099 { 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 if (transformer.getDebug()) 128 transformer.getTraceManager().fireTraceEvent(this); 129 130 try 131 { 132 XPathContext xctxt = transformer.getXPathContext(); 133 int sourceNode = xctxt.getCurrentNode(); 134 XObject value = m_selectExpression.execute(xctxt, sourceNode, this); 135 136 if (transformer.getDebug()) 137 transformer.getTraceManager().fireSelectedEvent(sourceNode, this, 138 "select", m_selectExpression, value); 139 140 SerializationHandler handler = transformer.getSerializationHandler(); 141 142 if (null != value) 143 { 144 int type = value.getType(); 145 String s; 146 147 switch (type) 148 { 149 case XObject.CLASS_BOOLEAN : 150 case XObject.CLASS_NUMBER : 151 case XObject.CLASS_STRING : 152 s = value.str(); 153 154 handler.characters(s.toCharArray(), 0, s.length()); 155 break; 156 case XObject.CLASS_NODESET : 157 158 // System.out.println(value); 159 DTMIterator nl = value.iter(); 160 161 // Copy the tree. 162 DTMTreeWalker tw = new TreeWalker2Result(transformer, handler); 163 int pos; 164 165 while (DTM.NULL != (pos = nl.nextNode())) 166 { 167 DTM dtm = xctxt.getDTMManager().getDTM(pos); 168 short t = dtm.getNodeType(pos); 169 170 // If we just copy the whole document, a startDoc and endDoc get 171 // generated, so we need to only walk the child nodes. 172 if (t == DTM.DOCUMENT_NODE) 173 { 174 for (int child = dtm.getFirstChild(pos); child != DTM.NULL; 175 child = dtm.getNextSibling(child)) 176 { 177 tw.traverse(child); 178 } 179 } 180 else if (t == DTM.ATTRIBUTE_NODE) 181 { 182 SerializerUtils.addAttribute(handler, pos); 183 } 184 else 185 { 186 tw.traverse(pos); 187 } 188 } 189 // nl.detach(); 190 break; 191 case XObject.CLASS_RTREEFRAG : 192 SerializerUtils.outputResultTreeFragment( 193 handler, value, transformer.getXPathContext()); 194 break; 195 default : 196 197 s = value.str(); 198 199 handler.characters(s.toCharArray(), 0, s.length()); 200 break; 201 } 202 } 203 204 // I don't think we want this. -sb 205 // if (transformer.getDebug()) 206 // transformer.getTraceManager().fireSelectedEvent(sourceNode, this, 207 // "endSelect", m_selectExpression, value); 208 209 } 210 catch(org.xml.sax.SAXException se) 211 { 212 throw new TransformerException(se); 213 } 214 finally 215 { 216 if (transformer.getDebug()) 217 transformer.getTraceManager().fireTraceEndEvent(this); 218 } 219 220 } 221 222 /** 223 * Add a child to the child list. 224 * 225 * @param newChild Child to add to this node's child list 226 * 227 * @return Child just added to child list 228 */ 229 public ElemTemplateElement appendChild(ElemTemplateElement newChild) 230 { 231 232 error(XSLTErrorResources.ER_CANNOT_ADD, 233 new Object[]{ newChild.getNodeName(), 234 this.getNodeName() }); //"Can not add " +((ElemTemplateElement)newChild).m_elemName + 235 236 //" to " + this.m_elemName); 237 return null; 238 } 239 240 /** 241 * Call the children visitors. 242 * @param visitor The visitor whose appropriate method will be called. 243 */ 244 protected void callChildVisitors(XSLTVisitor visitor, boolean callAttrs) 245 { 246 if(callAttrs) 247 m_selectExpression.getExpression().callVisitors(m_selectExpression, visitor); 248 super.callChildVisitors(visitor, callAttrs); 249 } 250 251 }