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 }