~vcs-imports/xena/trunk

« back to all changes in this revision

Viewing changes to ext/src/xalan-j_2_7_1/src/org/apache/xml/serializer/TreeWalker.java

  • Committer: matthewoliver
  • Date: 2009-12-10 03:18:07 UTC
  • Revision ID: vcs-imports@canonical.com-20091210031807-l086qguzdlljtkl9
Merged Xena Testing into Xena Stable for the Xena 5 release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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: TreeWalker.java,v 1.2 2009/12/10 03:18:07 matthewoliver Exp $
 
20
 */
 
21
package org.apache.xml.serializer;
 
22
 
 
23
import java.io.File;
 
24
 
 
25
import org.apache.xml.serializer.utils.AttList;
 
26
import org.apache.xml.serializer.utils.DOM2Helper;
 
27
import org.w3c.dom.Comment;
 
28
import org.w3c.dom.Element;
 
29
import org.w3c.dom.EntityReference;
 
30
import org.w3c.dom.NamedNodeMap;
 
31
import org.w3c.dom.Node;
 
32
import org.w3c.dom.ProcessingInstruction;
 
33
import org.w3c.dom.Text;
 
34
import org.xml.sax.ContentHandler;
 
35
import org.xml.sax.Locator;
 
36
import org.xml.sax.ext.LexicalHandler;
 
37
import org.xml.sax.helpers.LocatorImpl;
 
38
 
 
39
 
 
40
/**
 
41
 * This class does a pre-order walk of the DOM tree, calling a ContentHandler
 
42
 * interface as it goes.
 
43
 * 
 
44
 * This class is a copy of the one in org.apache.xml.utils. 
 
45
 * It exists to cut the serializers dependancy on that package.
 
46
 *  
 
47
 * @xsl.usage internal
 
48
 */
 
49
 
 
50
public final class TreeWalker
 
51
{
 
52
 
 
53
  /** Local reference to a ContentHandler          */
 
54
  final private ContentHandler m_contentHandler;
 
55
  /** 
 
56
   * If m_contentHandler is a SerializationHandler, then this is 
 
57
   * a reference to the same object. 
 
58
   */
 
59
  final private SerializationHandler m_Serializer;
 
60
 
 
61
  // ARGHH!!  JAXP Uses Xerces without setting the namespace processing to ON!
 
62
  // DOM2Helper m_dh = new DOM2Helper();
 
63
 
 
64
  /** DomHelper for this TreeWalker          */
 
65
  final protected DOM2Helper m_dh;
 
66
        
 
67
  /** Locator object for this TreeWalker          */
 
68
  final private LocatorImpl m_locator = new LocatorImpl();
 
69
 
 
70
  /**
 
71
   * Get the ContentHandler used for the tree walk.
 
72
   *
 
73
   * @return the ContentHandler used for the tree walk
 
74
   */
 
75
  public ContentHandler getContentHandler()
 
76
  {
 
77
    return m_contentHandler;
 
78
  }
 
79
  
 
80
  public TreeWalker(ContentHandler ch) {
 
81
      this(ch,null);
 
82
  }
 
83
  /**
 
84
   * Constructor.
 
85
   * @param   contentHandler The implemention of the
 
86
   * contentHandler operation (toXMLString, digest, ...)
 
87
   */
 
88
  public TreeWalker(ContentHandler contentHandler, String systemId)
 
89
  {
 
90
      // Set the content handler
 
91
      m_contentHandler = contentHandler;
 
92
      if (m_contentHandler instanceof SerializationHandler) {
 
93
          m_Serializer = (SerializationHandler) m_contentHandler;
 
94
      }
 
95
      else
 
96
          m_Serializer = null;
 
97
          
 
98
      // Set the system ID, if it is given
 
99
      m_contentHandler.setDocumentLocator(m_locator);
 
100
      if (systemId != null)
 
101
          m_locator.setSystemId(systemId);
 
102
      else {
 
103
          try {
 
104
            // Bug see Bugzilla  26741
 
105
            m_locator.setSystemId(System.getProperty("user.dir") + File.separator + "dummy.xsl");
 
106
           }
 
107
           catch (SecurityException se) {// user.dir not accessible from applet             
 
108
           }
 
109
      }
 
110
          
 
111
      // Set the document locator  
 
112
                if (m_contentHandler != null)
 
113
                        m_contentHandler.setDocumentLocator(m_locator);
 
114
                try {
 
115
                   // Bug see Bugzilla  26741
 
116
                  m_locator.setSystemId(System.getProperty("user.dir") + File.separator + "dummy.xsl");
 
117
                } 
 
118
                catch (SecurityException se){// user.dir not accessible from applet
 
119
                  
 
120
    }
 
121
    m_dh = new DOM2Helper();
 
122
  }
 
123
 
 
124
  /**
 
125
   * Perform a pre-order traversal non-recursive style.  
 
126
   *
 
127
   * Note that TreeWalker assumes that the subtree is intended to represent 
 
128
   * a complete (though not necessarily well-formed) document and, during a 
 
129
   * traversal, startDocument and endDocument will always be issued to the 
 
130
   * SAX listener.
 
131
   *  
 
132
   * @param pos Node in the tree where to start traversal
 
133
   *
 
134
   * @throws TransformerException
 
135
   */
 
136
  public void traverse(Node pos) throws org.xml.sax.SAXException
 
137
  {
 
138
 
 
139
    this.m_contentHandler.startDocument();
 
140
 
 
141
    Node top = pos;
 
142
 
 
143
    while (null != pos)
 
144
    {
 
145
      startNode(pos);
 
146
 
 
147
      Node nextNode = pos.getFirstChild();
 
148
 
 
149
      while (null == nextNode)
 
150
      {
 
151
        endNode(pos);
 
152
 
 
153
        if (top.equals(pos))
 
154
          break;
 
155
 
 
156
        nextNode = pos.getNextSibling();
 
157
 
 
158
        if (null == nextNode)
 
159
        {
 
160
          pos = pos.getParentNode();
 
161
 
 
162
          if ((null == pos) || (top.equals(pos)))
 
163
          {
 
164
            if (null != pos)
 
165
              endNode(pos);
 
166
 
 
167
            nextNode = null;
 
168
 
 
169
            break;
 
170
          }
 
171
        }
 
172
      }
 
173
 
 
174
      pos = nextNode;
 
175
    }
 
176
    this.m_contentHandler.endDocument();
 
177
  }
 
178
 
 
179
  /**
 
180
   * Perform a pre-order traversal non-recursive style.
 
181
 
 
182
   * Note that TreeWalker assumes that the subtree is intended to represent 
 
183
   * a complete (though not necessarily well-formed) document and, during a 
 
184
   * traversal, startDocument and endDocument will always be issued to the 
 
185
   * SAX listener.
 
186
   *
 
187
   * @param pos Node in the tree where to start traversal
 
188
   * @param top Node in the tree where to end traversal
 
189
   *
 
190
   * @throws TransformerException
 
191
   */
 
192
  public void traverse(Node pos, Node top) throws org.xml.sax.SAXException
 
193
  {
 
194
 
 
195
    this.m_contentHandler.startDocument();
 
196
    
 
197
    while (null != pos)
 
198
    {
 
199
      startNode(pos);
 
200
 
 
201
      Node nextNode = pos.getFirstChild();
 
202
 
 
203
      while (null == nextNode)
 
204
      {
 
205
        endNode(pos);
 
206
 
 
207
        if ((null != top) && top.equals(pos))
 
208
          break;
 
209
 
 
210
        nextNode = pos.getNextSibling();
 
211
 
 
212
        if (null == nextNode)
 
213
        {
 
214
          pos = pos.getParentNode();
 
215
 
 
216
          if ((null == pos) || ((null != top) && top.equals(pos)))
 
217
          {
 
218
            nextNode = null;
 
219
 
 
220
            break;
 
221
          }
 
222
        }
 
223
      }
 
224
 
 
225
      pos = nextNode;
 
226
    }
 
227
    this.m_contentHandler.endDocument();
 
228
  }
 
229
 
 
230
  /** Flag indicating whether following text to be processed is raw text          */
 
231
  boolean nextIsRaw = false;
 
232
  
 
233
  /**
 
234
   * Optimized dispatch of characters.
 
235
   */
 
236
  private final void dispatachChars(Node node)
 
237
     throws org.xml.sax.SAXException
 
238
  {
 
239
    if(m_Serializer != null)
 
240
    {
 
241
      this.m_Serializer.characters(node);
 
242
    }
 
243
    else
 
244
    {
 
245
      String data = ((Text) node).getData();
 
246
      this.m_contentHandler.characters(data.toCharArray(), 0, data.length());
 
247
    }
 
248
  }
 
249
 
 
250
  /**
 
251
   * Start processing given node
 
252
   *
 
253
   *
 
254
   * @param node Node to process
 
255
   *
 
256
   * @throws org.xml.sax.SAXException
 
257
   */
 
258
  protected void startNode(Node node) throws org.xml.sax.SAXException
 
259
  {
 
260
 
 
261
//   TODO: <REVIEW>
 
262
//    A Serializer implements ContentHandler, but not NodeConsumer
 
263
//    so drop this reference to NodeConsumer which would otherwise
 
264
//    pull in all sorts of things
 
265
//    if (m_contentHandler instanceof NodeConsumer)
 
266
//    {
 
267
//      ((NodeConsumer) m_contentHandler).setOriginatingNode(node);
 
268
//    }
 
269
//    TODO: </REVIEW>
 
270
                
 
271
                if (node instanceof Locator)
 
272
                {
 
273
                        Locator loc = (Locator)node;
 
274
                        m_locator.setColumnNumber(loc.getColumnNumber());
 
275
                        m_locator.setLineNumber(loc.getLineNumber());
 
276
                        m_locator.setPublicId(loc.getPublicId());
 
277
                        m_locator.setSystemId(loc.getSystemId());
 
278
                }
 
279
                else
 
280
                {
 
281
                        m_locator.setColumnNumber(0);
 
282
      m_locator.setLineNumber(0);
 
283
                }
 
284
 
 
285
    switch (node.getNodeType())
 
286
    {
 
287
    case Node.COMMENT_NODE :
 
288
    {
 
289
      String data = ((Comment) node).getData();
 
290
 
 
291
      if (m_contentHandler instanceof LexicalHandler)
 
292
      {
 
293
        LexicalHandler lh = ((LexicalHandler) this.m_contentHandler);
 
294
 
 
295
        lh.comment(data.toCharArray(), 0, data.length());
 
296
      }
 
297
    }
 
298
    break;
 
299
    case Node.DOCUMENT_FRAGMENT_NODE :
 
300
 
 
301
      // ??;
 
302
      break;
 
303
    case Node.DOCUMENT_NODE :
 
304
    
 
305
      break;
 
306
    case Node.ELEMENT_NODE :
 
307
      Element elem_node = (Element) node;
 
308
      {
 
309
          // Make sure the namespace node
 
310
          // for the element itself is declared
 
311
          // to the ContentHandler
 
312
          String uri = elem_node.getNamespaceURI();
 
313
          if (uri != null) {
 
314
              String prefix = elem_node.getPrefix();
 
315
              if (prefix==null)
 
316
                prefix="";
 
317
              this.m_contentHandler.startPrefixMapping(prefix,uri);              
 
318
          }
 
319
      }
 
320
      NamedNodeMap atts = elem_node.getAttributes();
 
321
      int nAttrs = atts.getLength();
 
322
      // System.out.println("TreeWalker#startNode: "+node.getNodeName());
 
323
 
 
324
      
 
325
      // Make sure the namespace node of
 
326
      // each attribute is declared to the ContentHandler
 
327
      for (int i = 0; i < nAttrs; i++)
 
328
      {
 
329
        final Node attr = atts.item(i);
 
330
        final String attrName = attr.getNodeName();
 
331
        final int colon = attrName.indexOf(':');
 
332
        final String prefix;
 
333
 
 
334
        // System.out.println("TreeWalker#startNode: attr["+i+"] = "+attrName+", "+attr.getNodeValue());
 
335
        if (attrName.equals("xmlns") || attrName.startsWith("xmlns:"))
 
336
        {
 
337
          // Use "" instead of null, as Xerces likes "" for the 
 
338
          // name of the default namespace.  Fix attributed 
 
339
          // to "Steven Murray" <smurray@ebt.com>.
 
340
          if (colon < 0)
 
341
            prefix = "";
 
342
          else
 
343
            prefix = attrName.substring(colon + 1);
 
344
 
 
345
          this.m_contentHandler.startPrefixMapping(prefix,
 
346
                                                   attr.getNodeValue());
 
347
        }
 
348
        else if (colon > 0) {
 
349
            prefix = attrName.substring(0,colon);
 
350
            String uri = attr.getNamespaceURI();
 
351
            if (uri != null)
 
352
                this.m_contentHandler.startPrefixMapping(prefix,uri);
 
353
        }        
 
354
      }
 
355
 
 
356
      String ns = m_dh.getNamespaceOfNode(node);
 
357
      if(null == ns)
 
358
        ns = "";
 
359
      this.m_contentHandler.startElement(ns,
 
360
                                         m_dh.getLocalNameOfNode(node),
 
361
                                         node.getNodeName(),
 
362
                                         new AttList(atts, m_dh));
 
363
      break;
 
364
    case Node.PROCESSING_INSTRUCTION_NODE :
 
365
    {
 
366
      ProcessingInstruction pi = (ProcessingInstruction) node;
 
367
      String name = pi.getNodeName();
 
368
 
 
369
      // String data = pi.getData();
 
370
      if (name.equals("xslt-next-is-raw"))
 
371
      {
 
372
        nextIsRaw = true;
 
373
      }
 
374
      else
 
375
      {
 
376
        this.m_contentHandler.processingInstruction(pi.getNodeName(),
 
377
                                                    pi.getData());
 
378
      }
 
379
    }
 
380
    break;
 
381
    case Node.CDATA_SECTION_NODE :
 
382
    {
 
383
      boolean isLexH = (m_contentHandler instanceof LexicalHandler);
 
384
      LexicalHandler lh = isLexH
 
385
                          ? ((LexicalHandler) this.m_contentHandler) : null;
 
386
 
 
387
      if (isLexH)
 
388
      {
 
389
        lh.startCDATA();
 
390
      }
 
391
      
 
392
      dispatachChars(node);
 
393
 
 
394
      {
 
395
        if (isLexH)
 
396
        {
 
397
          lh.endCDATA();
 
398
        }
 
399
      }
 
400
    }
 
401
    break;
 
402
    case Node.TEXT_NODE :
 
403
    {
 
404
      //String data = ((Text) node).getData();
 
405
 
 
406
      if (nextIsRaw)
 
407
      {
 
408
        nextIsRaw = false;
 
409
 
 
410
        m_contentHandler.processingInstruction(javax.xml.transform.Result.PI_DISABLE_OUTPUT_ESCAPING, "");
 
411
        dispatachChars(node);
 
412
        m_contentHandler.processingInstruction(javax.xml.transform.Result.PI_ENABLE_OUTPUT_ESCAPING, "");
 
413
      }
 
414
      else
 
415
      {
 
416
        dispatachChars(node);
 
417
      }
 
418
    }
 
419
    break;
 
420
    case Node.ENTITY_REFERENCE_NODE :
 
421
    {
 
422
      EntityReference eref = (EntityReference) node;
 
423
 
 
424
      if (m_contentHandler instanceof LexicalHandler)
 
425
      {
 
426
        ((LexicalHandler) this.m_contentHandler).startEntity(
 
427
          eref.getNodeName());
 
428
      }
 
429
      else
 
430
      {
 
431
 
 
432
        // warning("Can not output entity to a pure SAX ContentHandler");
 
433
      }
 
434
    }
 
435
    break;
 
436
    default :
 
437
    }
 
438
  }
 
439
 
 
440
  /**
 
441
   * End processing of given node 
 
442
   *
 
443
   *
 
444
   * @param node Node we just finished processing
 
445
   *
 
446
   * @throws org.xml.sax.SAXException
 
447
   */
 
448
  protected void endNode(Node node) throws org.xml.sax.SAXException
 
449
  {
 
450
 
 
451
    switch (node.getNodeType())
 
452
    {
 
453
    case Node.DOCUMENT_NODE :
 
454
      break;
 
455
      
 
456
    case Node.ELEMENT_NODE :
 
457
      String ns = m_dh.getNamespaceOfNode(node);
 
458
      if(null == ns)
 
459
        ns = "";
 
460
      this.m_contentHandler.endElement(ns,
 
461
                                         m_dh.getLocalNameOfNode(node),
 
462
                                         node.getNodeName());
 
463
 
 
464
      if (m_Serializer == null) {
 
465
      // Don't bother with endPrefixMapping calls if the ContentHandler is a
 
466
      // SerializationHandler because SerializationHandler's ignore the
 
467
      // endPrefixMapping() calls anyways. . . .  This is an optimization.    
 
468
      Element elem_node = (Element) node;    
 
469
      NamedNodeMap atts = elem_node.getAttributes();
 
470
      int nAttrs = atts.getLength();
 
471
 
 
472
      // do the endPrefixMapping calls in reverse order 
 
473
      // of the startPrefixMapping calls
 
474
      for (int i = (nAttrs-1); 0 <= i; i--)
 
475
      {
 
476
        final Node attr = atts.item(i);
 
477
        final String attrName = attr.getNodeName();
 
478
        final int colon = attrName.indexOf(':');
 
479
        final String prefix;
 
480
 
 
481
        if (attrName.equals("xmlns") || attrName.startsWith("xmlns:"))
 
482
        {
 
483
          // Use "" instead of null, as Xerces likes "" for the 
 
484
          // name of the default namespace.  Fix attributed 
 
485
          // to "Steven Murray" <smurray@ebt.com>.
 
486
          if (colon < 0)
 
487
            prefix = "";
 
488
          else
 
489
            prefix = attrName.substring(colon + 1);
 
490
 
 
491
          this.m_contentHandler.endPrefixMapping(prefix);
 
492
        }
 
493
        else if (colon > 0) {
 
494
            prefix = attrName.substring(0, colon);
 
495
            this.m_contentHandler.endPrefixMapping(prefix);
 
496
        }
 
497
      }
 
498
      {
 
499
          String uri = elem_node.getNamespaceURI();
 
500
          if (uri != null) {
 
501
              String prefix = elem_node.getPrefix();
 
502
              if (prefix==null)
 
503
                prefix="";
 
504
              this.m_contentHandler.endPrefixMapping(prefix);              
 
505
          }
 
506
      }
 
507
      }
 
508
      break;
 
509
    case Node.CDATA_SECTION_NODE :
 
510
      break;
 
511
    case Node.ENTITY_REFERENCE_NODE :
 
512
    {
 
513
      EntityReference eref = (EntityReference) node;
 
514
 
 
515
      if (m_contentHandler instanceof LexicalHandler)
 
516
      {
 
517
        LexicalHandler lh = ((LexicalHandler) this.m_contentHandler);
 
518
 
 
519
        lh.endEntity(eref.getNodeName());
 
520
      }
 
521
    }
 
522
    break;
 
523
    default :
 
524
    }
 
525
  }
 
526
}  //TreeWalker
 
527