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 */
21package org.apache.xalan.templates;
22
23import javax.xml.transform.TransformerException;
24
25import org.apache.xalan.res.XSLTErrorResources;
26import org.apache.xalan.transformer.TransformerImpl;
27import org.apache.xalan.transformer.TreeWalker2Result;
28import org.apache.xml.dtm.DTM;
29import org.apache.xml.dtm.DTMIterator;
30import org.apache.xml.dtm.ref.DTMTreeWalker;
31import org.apache.xalan.serialize.SerializerUtils;
32import org.apache.xml.serializer.SerializationHandler;
33import org.apache.xpath.XPath;
34import org.apache.xpath.XPathContext;
35import 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 */
46public 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