1/*
2 * reserved comment block
3 * DO NOT REMOVE OR ALTER!
4 */
5/*
6 * Licensed to the Apache Software Foundation (ASF) under one or more
7 * contributor license agreements.  See the NOTICE file distributed with
8 * this work for additional information regarding copyright ownership.
9 * The ASF licenses this file to You under the Apache License, Version 2.0
10 * (the "License"); you may not use this file except in compliance with
11 * the License.  You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 */
21
22package com.sun.org.apache.xml.internal.dtm.ref;
23
24import com.sun.org.apache.xml.internal.dtm.DTM;
25import com.sun.org.apache.xml.internal.utils.NodeConsumer;
26import com.sun.org.apache.xml.internal.utils.XMLString;
27
28import org.xml.sax.ContentHandler;
29import org.xml.sax.ext.LexicalHandler;
30
31/**
32 * This class does a pre-order walk of the DTM tree, calling a ContentHandler
33 * interface as it goes. As such, it's more like the Visitor design pattern
34 * than like the DOM's TreeWalker.
35 *
36 * I think normally this class should not be needed, because
37 * of DTM#dispatchToEvents.
38 * @xsl.usage advanced
39 */
40public class DTMTreeWalker
41{
42
43  /** Local reference to a ContentHandler          */
44  private ContentHandler m_contentHandler = null;
45
46  /** DomHelper for this TreeWalker          */
47  protected DTM m_dtm;
48
49  /**
50   * Set the DTM to be traversed.
51   *
52   * @param dtm The Document Table Model to be used.
53   */
54  public void setDTM(DTM dtm)
55  {
56    m_dtm = dtm;
57  }
58
59  /**
60   * Get the ContentHandler used for the tree walk.
61   *
62   * @return the ContentHandler used for the tree walk
63   */
64  public ContentHandler getcontentHandler()
65  {
66    return m_contentHandler;
67  }
68
69  /**
70   * Set the ContentHandler used for the tree walk.
71   *
72   * @param ch the ContentHandler to be the result of the tree walk.
73   */
74  public void setcontentHandler(ContentHandler ch)
75  {
76    m_contentHandler = ch;
77  }
78
79
80  /**
81   * Constructor.
82   */
83  public DTMTreeWalker()
84  {
85  }
86
87  /**
88   * Constructor.
89   * @param   contentHandler The implemention of the
90   * contentHandler operation (toXMLString, digest, ...)
91   */
92  public DTMTreeWalker(ContentHandler contentHandler, DTM dtm)
93  {
94    this.m_contentHandler = contentHandler;
95    m_dtm = dtm;
96  }
97
98  /** Perform a non-recursive pre-order/post-order traversal,
99   * operating as a Visitor. startNode (preorder) and endNode
100   * (postorder) are invoked for each node as we traverse over them,
101   * with the result that the node is written out to m_contentHandler.
102   *
103   * @param pos Node in the tree at which to start (and end) traversal --
104   * in other words, the root of the subtree to traverse over.
105   *
106   * @throws TransformerException */
107  public void traverse(int pos) throws org.xml.sax.SAXException
108  {
109    // %REVIEW% Why isn't this just traverse(pos,pos)?
110
111    int top = pos;              // Remember the root of this subtree
112
113    while (DTM.NULL != pos)
114    {
115      startNode(pos);
116      int nextNode = m_dtm.getFirstChild(pos);
117      while (DTM.NULL == nextNode)
118      {
119        endNode(pos);
120
121        if (top == pos)
122          break;
123
124        nextNode = m_dtm.getNextSibling(pos);
125
126        if (DTM.NULL == nextNode)
127        {
128          pos = m_dtm.getParent(pos);
129
130          if ((DTM.NULL == pos) || (top == pos))
131          {
132            // %REVIEW% This condition isn't tested in traverse(pos,top)
133            // -- bug?
134            if (DTM.NULL != pos)
135              endNode(pos);
136
137            nextNode = DTM.NULL;
138
139            break;
140          }
141        }
142      }
143
144      pos = nextNode;
145    }
146  }
147
148  /** Perform a non-recursive pre-order/post-order traversal,
149   * operating as a Visitor. startNode (preorder) and endNode
150   * (postorder) are invoked for each node as we traverse over them,
151   * with the result that the node is written out to m_contentHandler.
152   *
153   * @param pos Node in the tree where to start traversal
154   * @param top Node in the tree where to end traversal.
155   * If top==DTM.NULL, run through end of document.
156   *
157   * @throws TransformerException
158   */
159  public void traverse(int pos, int top) throws org.xml.sax.SAXException
160  {
161    // %OPT% Can we simplify the loop conditionals by adding:
162    //          if(top==DTM.NULL) top=0
163    // -- or by simply ignoring this case and relying on the fact that
164    // pos will never equal DTM.NULL until we're ready to exit?
165
166    while (DTM.NULL != pos)
167    {
168      startNode(pos);
169      int nextNode = m_dtm.getFirstChild(pos);
170      while (DTM.NULL == nextNode)
171      {
172        endNode(pos);
173
174        if ((DTM.NULL != top) && top == pos)
175          break;
176
177        nextNode = m_dtm.getNextSibling(pos);
178
179        if (DTM.NULL == nextNode)
180        {
181          pos = m_dtm.getParent(pos);
182
183          if ((DTM.NULL == pos) || ((DTM.NULL != top) && (top == pos)))
184          {
185            nextNode = DTM.NULL;
186
187            break;
188          }
189        }
190      }
191
192      pos = nextNode;
193    }
194  }
195
196  /** Flag indicating whether following text to be processed is raw text          */
197  boolean nextIsRaw = false;
198
199  /**
200   * Optimized dispatch of characters.
201   */
202  private final void dispatachChars(int node)
203     throws org.xml.sax.SAXException
204  {
205    m_dtm.dispatchCharactersEvents(node, m_contentHandler, false);
206  }
207
208  /**
209   * Start processing given node
210   *
211   *
212   * @param node Node to process
213   *
214   * @throws org.xml.sax.SAXException
215   */
216  protected void startNode(int node) throws org.xml.sax.SAXException
217  {
218
219    if (m_contentHandler instanceof NodeConsumer)
220    {
221      // %TBD%
222//      ((NodeConsumer) m_contentHandler).setOriginatingNode(node);
223    }
224
225    switch (m_dtm.getNodeType(node))
226    {
227    case DTM.COMMENT_NODE :
228    {
229      XMLString data = m_dtm.getStringValue(node);
230
231      if (m_contentHandler instanceof LexicalHandler)
232      {
233        LexicalHandler lh = ((LexicalHandler) this.m_contentHandler);
234        data.dispatchAsComment(lh);
235      }
236    }
237    break;
238    case DTM.DOCUMENT_FRAGMENT_NODE :
239
240      // ??;
241      break;
242    case DTM.DOCUMENT_NODE :
243      this.m_contentHandler.startDocument();
244      break;
245    case DTM.ELEMENT_NODE :
246      DTM dtm = m_dtm;
247
248      for (int nsn = dtm.getFirstNamespaceNode(node, true); DTM.NULL != nsn;
249           nsn = dtm.getNextNamespaceNode(node, nsn, true))
250      {
251        // String prefix = dtm.getPrefix(nsn);
252        String prefix = dtm.getNodeNameX(nsn);
253
254        this.m_contentHandler.startPrefixMapping(prefix, dtm.getNodeValue(nsn));
255
256      }
257
258      // System.out.println("m_dh.getNamespaceOfNode(node): "+m_dh.getNamespaceOfNode(node));
259      // System.out.println("m_dh.getLocalNameOfNode(node): "+m_dh.getLocalNameOfNode(node));
260      String ns = dtm.getNamespaceURI(node);
261      if(null == ns)
262        ns = "";
263
264      // %OPT% !!
265      org.xml.sax.helpers.AttributesImpl attrs =
266                            new org.xml.sax.helpers.AttributesImpl();
267
268      for (int i = dtm.getFirstAttribute(node);
269           i != DTM.NULL;
270           i = dtm.getNextAttribute(i))
271      {
272        attrs.addAttribute(dtm.getNamespaceURI(i),
273                           dtm.getLocalName(i),
274                           dtm.getNodeName(i),
275                           "CDATA",
276                           dtm.getNodeValue(i));
277      }
278
279
280      this.m_contentHandler.startElement(ns,
281                                         m_dtm.getLocalName(node),
282                                         m_dtm.getNodeName(node),
283                                         attrs);
284      break;
285    case DTM.PROCESSING_INSTRUCTION_NODE :
286    {
287      String name = m_dtm.getNodeName(node);
288
289      // String data = pi.getData();
290      if (name.equals("xslt-next-is-raw"))
291      {
292        nextIsRaw = true;
293      }
294      else
295      {
296        this.m_contentHandler.processingInstruction(name,
297                                                    m_dtm.getNodeValue(node));
298      }
299    }
300    break;
301    case DTM.CDATA_SECTION_NODE :
302    {
303      boolean isLexH = (m_contentHandler instanceof LexicalHandler);
304      LexicalHandler lh = isLexH
305                          ? ((LexicalHandler) this.m_contentHandler) : null;
306
307      if (isLexH)
308      {
309        lh.startCDATA();
310      }
311
312      dispatachChars(node);
313
314      {
315        if (isLexH)
316        {
317          lh.endCDATA();
318        }
319      }
320    }
321    break;
322    case DTM.TEXT_NODE :
323    {
324      if (nextIsRaw)
325      {
326        nextIsRaw = false;
327
328        m_contentHandler.processingInstruction(javax.xml.transform.Result.PI_DISABLE_OUTPUT_ESCAPING, "");
329        dispatachChars(node);
330        m_contentHandler.processingInstruction(javax.xml.transform.Result.PI_ENABLE_OUTPUT_ESCAPING, "");
331      }
332      else
333      {
334        dispatachChars(node);
335      }
336    }
337    break;
338    case DTM.ENTITY_REFERENCE_NODE :
339    {
340      if (m_contentHandler instanceof LexicalHandler)
341      {
342        ((LexicalHandler) this.m_contentHandler).startEntity(
343          m_dtm.getNodeName(node));
344      }
345      else
346      {
347
348        // warning("Can not output entity to a pure SAX ContentHandler");
349      }
350    }
351    break;
352    default :
353    }
354  }
355
356  /**
357   * End processing of given node
358   *
359   *
360   * @param node Node we just finished processing
361   *
362   * @throws org.xml.sax.SAXException
363   */
364  protected void endNode(int node) throws org.xml.sax.SAXException
365  {
366
367    switch (m_dtm.getNodeType(node))
368    {
369    case DTM.DOCUMENT_NODE :
370      this.m_contentHandler.endDocument();
371      break;
372    case DTM.ELEMENT_NODE :
373      String ns = m_dtm.getNamespaceURI(node);
374      if(null == ns)
375        ns = "";
376      this.m_contentHandler.endElement(ns,
377                                         m_dtm.getLocalName(node),
378                                         m_dtm.getNodeName(node));
379
380      for (int nsn = m_dtm.getFirstNamespaceNode(node, true); DTM.NULL != nsn;
381           nsn = m_dtm.getNextNamespaceNode(node, nsn, true))
382      {
383        // String prefix = m_dtm.getPrefix(nsn);
384        String prefix = m_dtm.getNodeNameX(nsn);
385
386        this.m_contentHandler.endPrefixMapping(prefix);
387      }
388      break;
389    case DTM.CDATA_SECTION_NODE :
390      break;
391    case DTM.ENTITY_REFERENCE_NODE :
392    {
393      if (m_contentHandler instanceof LexicalHandler)
394      {
395        LexicalHandler lh = ((LexicalHandler) this.m_contentHandler);
396
397        lh.endEntity(m_dtm.getNodeName(node));
398      }
399    }
400    break;
401    default :
402    }
403  }
404}  //TreeWalker
405