1 /*
2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
3 */
4 /*
5 * Licensed to the Apache Software Foundation (ASF) under one or more
6 * contributor license agreements. See the NOTICE file distributed with
7 * this work for additional information regarding copyright ownership.
8 * The ASF licenses this file to You under the Apache License, Version 2.0
9 * (the "License"); you may not use this file except in compliance with
10 * the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20 package com.sun.org.apache.xml.internal.serializer;
21
22 import com.sun.org.apache.xalan.internal.utils.SecuritySupport;
23 import java.io.File;
24
25 import com.sun.org.apache.xml.internal.serializer.utils.AttList;
26 import com.sun.org.apache.xml.internal.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
35 import org.xml.sax.ContentHandler;
36 import org.xml.sax.Locator;
37 import org.xml.sax.ext.LexicalHandler;
38 import org.xml.sax.helpers.LocatorImpl;
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 com.sun.org.apache.xml.internal.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 } else {
95 m_Serializer = null;
96 }
97 // Set the system ID, if it is given
98 m_contentHandler.setDocumentLocator(m_locator);
99 if (systemId != null) {
100 m_locator.setSystemId(systemId);
101 }
102
103 m_dh = new DOM2Helper();
104 }
105
106 /**
107 * Perform a pre-order traversal non-recursive style.
108 *
109 * Note that TreeWalker assumes that the subtree is intended to represent
110 * a complete (though not necessarily well-formed) document and, during a
111 * traversal, startDocument and endDocument will always be issued to the
112 * SAX listener.
113 *
114 * @param pos Node in the tree where to start traversal
115 *
116 * @throws TransformerException
117 */
118 public void traverse(Node pos) throws org.xml.sax.SAXException
119 {
120
121 this.m_contentHandler.startDocument();
122
123 Node top = pos;
192 nextNode = pos.getNextSibling();
193
194 if (null == nextNode)
195 {
196 pos = pos.getParentNode();
197
198 if ((null == pos) || ((null != top) && top.equals(pos)))
199 {
200 nextNode = null;
201
202 break;
203 }
204 }
205 }
206
207 pos = nextNode;
208 }
209 this.m_contentHandler.endDocument();
210 }
211
212 /** Flag indicating whether following text to be processed is raw text */
213 boolean nextIsRaw = false;
214
215 /**
216 * Optimized dispatch of characters.
217 */
218 private final void dispatachChars(Node node)
219 throws org.xml.sax.SAXException
220 {
221 if(m_Serializer != null)
222 {
223 this.m_Serializer.characters(node);
224 }
225 else
226 {
227 String data = ((Text) node).getData();
228 this.m_contentHandler.characters(data.toCharArray(), 0, data.length());
229 }
230 }
231
232 /**
296 String prefix = elem_node.getPrefix();
297 if (prefix==null)
298 prefix="";
299 this.m_contentHandler.startPrefixMapping(prefix,uri);
300 }
301 }
302 NamedNodeMap atts = elem_node.getAttributes();
303 int nAttrs = atts.getLength();
304 // System.out.println("TreeWalker#startNode: "+node.getNodeName());
305
306
307 // Make sure the namespace node of
308 // each attribute is declared to the ContentHandler
309 for (int i = 0; i < nAttrs; i++)
310 {
311 final Node attr = atts.item(i);
312 final String attrName = attr.getNodeName();
313 final int colon = attrName.indexOf(':');
314 final String prefix;
315
316 // System.out.println("TreeWalker#startNode: attr["+i+"] = "+attrName+", "+attr.getNodeValue());
317 if (attrName.equals("xmlns") || attrName.startsWith("xmlns:"))
318 {
319 // Use "" instead of null, as Xerces likes "" for the
320 // name of the default namespace. Fix attributed
321 // to "Steven Murray" <smurray@ebt.com>.
322 if (colon < 0)
323 prefix = "";
324 else
325 prefix = attrName.substring(colon + 1);
326
327 this.m_contentHandler.startPrefixMapping(prefix,
328 attr.getNodeValue());
329 }
330 else if (colon > 0) {
331 prefix = attrName.substring(0,colon);
332 String uri = attr.getNamespaceURI();
333 if (uri != null)
334 this.m_contentHandler.startPrefixMapping(prefix,uri);
335 }
336 }
337
338 String ns = m_dh.getNamespaceOfNode(node);
339 if(null == ns)
340 ns = "";
341 this.m_contentHandler.startElement(ns,
342 m_dh.getLocalNameOfNode(node),
343 node.getNodeName(),
344 new AttList(atts, m_dh));
345 break;
346 case Node.PROCESSING_INSTRUCTION_NODE :
347 {
348 ProcessingInstruction pi = (ProcessingInstruction) node;
349 String name = pi.getNodeName();
350
351 // String data = pi.getData();
352 if (name.equals("xslt-next-is-raw"))
353 {
354 nextIsRaw = true;
355 }
356 else
357 {
358 this.m_contentHandler.processingInstruction(pi.getNodeName(),
359 pi.getData());
360 }
361 }
362 break;
363 case Node.CDATA_SECTION_NODE :
364 {
372 }
373
374 dispatachChars(node);
375
376 {
377 if (isLexH)
378 {
379 lh.endCDATA();
380 }
381 }
382 }
383 break;
384 case Node.TEXT_NODE :
385 {
386 //String data = ((Text) node).getData();
387
388 if (nextIsRaw)
389 {
390 nextIsRaw = false;
391
392 m_contentHandler.processingInstruction(javax.xml.transform.Result.PI_DISABLE_OUTPUT_ESCAPING, "");
393 dispatachChars(node);
394 m_contentHandler.processingInstruction(javax.xml.transform.Result.PI_ENABLE_OUTPUT_ESCAPING, "");
395 }
396 else
397 {
398 dispatachChars(node);
399 }
400 }
401 break;
402 case Node.ENTITY_REFERENCE_NODE :
403 {
404 EntityReference eref = (EntityReference) node;
405
406 if (m_contentHandler instanceof LexicalHandler)
407 {
408 ((LexicalHandler) this.m_contentHandler).startEntity(
409 eref.getNodeName());
410 }
411 else
412 {
413
414 // warning("Can not output entity to a pure SAX ContentHandler");
419 }
420 }
421
422 /**
423 * End processing of given node
424 *
425 *
426 * @param node Node we just finished processing
427 *
428 * @throws org.xml.sax.SAXException
429 */
430 protected void endNode(Node node) throws org.xml.sax.SAXException
431 {
432
433 switch (node.getNodeType())
434 {
435 case Node.DOCUMENT_NODE :
436 break;
437
438 case Node.ELEMENT_NODE :
439 String ns = m_dh.getNamespaceOfNode(node);
440 if(null == ns)
441 ns = "";
442 this.m_contentHandler.endElement(ns,
443 m_dh.getLocalNameOfNode(node),
444 node.getNodeName());
445
446 if (m_Serializer == null) {
447 // Don't bother with endPrefixMapping calls if the ContentHandler is a
448 // SerializationHandler because SerializationHandler's ignore the
449 // endPrefixMapping() calls anyways. . . . This is an optimization.
450 Element elem_node = (Element) node;
451 NamedNodeMap atts = elem_node.getAttributes();
452 int nAttrs = atts.getLength();
453
454 // do the endPrefixMapping calls in reverse order
455 // of the startPrefixMapping calls
456 for (int i = (nAttrs-1); 0 <= i; i--)
457 {
458 final Node attr = atts.item(i);
459 final String attrName = attr.getNodeName();
460 final int colon = attrName.indexOf(':');
461 final String prefix;
462
463 if (attrName.equals("xmlns") || attrName.startsWith("xmlns:"))
|
1 /*
2 * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
3 */
4 /*
5 * Licensed to the Apache Software Foundation (ASF) under one or more
6 * contributor license agreements. See the NOTICE file distributed with
7 * this work for additional information regarding copyright ownership.
8 * The ASF licenses this file to You under the Apache License, Version 2.0
9 * (the "License"); you may not use this file except in compliance with
10 * the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21 package com.sun.org.apache.xml.internal.serializer;
22
23 import com.sun.org.apache.xml.internal.utils.AttList;
24 import com.sun.org.apache.xml.internal.utils.DOM2Helper;
25 import javax.xml.transform.Result;
26 import org.w3c.dom.Comment;
27 import org.w3c.dom.Element;
28 import org.w3c.dom.EntityReference;
29 import org.w3c.dom.NamedNodeMap;
30 import org.w3c.dom.Node;
31 import org.w3c.dom.ProcessingInstruction;
32 import org.w3c.dom.Text;
33 import org.xml.sax.ContentHandler;
34 import org.xml.sax.Locator;
35 import org.xml.sax.ext.LexicalHandler;
36 import org.xml.sax.helpers.LocatorImpl;
37
38 /**
39 * This class does a pre-order walk of the DOM tree, calling a ContentHandler
40 * interface as it goes.
41 *
42 * This class is a copy of the one in com.sun.org.apache.xml.internal.utils.
43 * It exists to cut the serializers dependancy on that package.
44 *
45 * @xsl.usage internal
46 */
47
48 public final class TreeWalker
49 {
50
51 /** Local reference to a ContentHandler */
52 final private ContentHandler m_contentHandler;
53 /**
54 * If m_contentHandler is a SerializationHandler, then this is
55 * a reference to the same object.
56 */
57 final private SerializationHandler m_Serializer;
58
59 /** Locator object for this TreeWalker */
60 final private LocatorImpl m_locator = new LocatorImpl();
61
62 /**
63 * Get the ContentHandler used for the tree walk.
64 *
65 * @return the ContentHandler used for the tree walk
66 */
67 public ContentHandler getContentHandler()
68 {
69 return m_contentHandler;
70 }
71
72 public TreeWalker(ContentHandler ch) {
73 this(ch, null);
74 }
75 /**
76 * Constructor.
77 * @param contentHandler The implemention of the
78 * contentHandler operation (toXMLString, digest, ...)
79 */
80 public TreeWalker(ContentHandler contentHandler, String systemId)
81 {
82 // Set the content handler
83 m_contentHandler = contentHandler;
84 if (m_contentHandler instanceof SerializationHandler) {
85 m_Serializer = (SerializationHandler) m_contentHandler;
86 } else {
87 m_Serializer = null;
88 }
89 // Set the system ID, if it is given
90 m_contentHandler.setDocumentLocator(m_locator);
91 if (systemId != null) {
92 m_locator.setSystemId(systemId);
93 }
94 }
95
96 /**
97 * Perform a pre-order traversal non-recursive style.
98 *
99 * Note that TreeWalker assumes that the subtree is intended to represent
100 * a complete (though not necessarily well-formed) document and, during a
101 * traversal, startDocument and endDocument will always be issued to the
102 * SAX listener.
103 *
104 * @param pos Node in the tree where to start traversal
105 *
106 * @throws TransformerException
107 */
108 public void traverse(Node pos) throws org.xml.sax.SAXException
109 {
110
111 this.m_contentHandler.startDocument();
112
113 Node top = pos;
182 nextNode = pos.getNextSibling();
183
184 if (null == nextNode)
185 {
186 pos = pos.getParentNode();
187
188 if ((null == pos) || ((null != top) && top.equals(pos)))
189 {
190 nextNode = null;
191
192 break;
193 }
194 }
195 }
196
197 pos = nextNode;
198 }
199 this.m_contentHandler.endDocument();
200 }
201
202 // Flag indicating whether following text to be processed is raw text
203 boolean nextIsRaw = false;
204
205 /**
206 * Optimized dispatch of characters.
207 */
208 private final void dispatachChars(Node node)
209 throws org.xml.sax.SAXException
210 {
211 if(m_Serializer != null)
212 {
213 this.m_Serializer.characters(node);
214 }
215 else
216 {
217 String data = ((Text) node).getData();
218 this.m_contentHandler.characters(data.toCharArray(), 0, data.length());
219 }
220 }
221
222 /**
286 String prefix = elem_node.getPrefix();
287 if (prefix==null)
288 prefix="";
289 this.m_contentHandler.startPrefixMapping(prefix,uri);
290 }
291 }
292 NamedNodeMap atts = elem_node.getAttributes();
293 int nAttrs = atts.getLength();
294 // System.out.println("TreeWalker#startNode: "+node.getNodeName());
295
296
297 // Make sure the namespace node of
298 // each attribute is declared to the ContentHandler
299 for (int i = 0; i < nAttrs; i++)
300 {
301 final Node attr = atts.item(i);
302 final String attrName = attr.getNodeName();
303 final int colon = attrName.indexOf(':');
304 final String prefix;
305
306 if (attrName.equals("xmlns") || attrName.startsWith("xmlns:"))
307 {
308 // Use "" instead of null, as Xerces likes "" for the
309 // name of the default namespace. Fix attributed
310 // to "Steven Murray" <smurray@ebt.com>.
311 if (colon < 0)
312 prefix = "";
313 else
314 prefix = attrName.substring(colon + 1);
315
316 this.m_contentHandler.startPrefixMapping(prefix,
317 attr.getNodeValue());
318 }
319 else if (colon > 0) {
320 prefix = attrName.substring(0,colon);
321 String uri = attr.getNamespaceURI();
322 if (uri != null)
323 this.m_contentHandler.startPrefixMapping(prefix,uri);
324 }
325 }
326
327 String ns = DOM2Helper.getNamespaceOfNode(node);
328 if(null == ns)
329 ns = "";
330 this.m_contentHandler.startElement(ns,
331 DOM2Helper.getLocalNameOfNode(node),
332 node.getNodeName(),
333 new AttList(atts));
334 break;
335 case Node.PROCESSING_INSTRUCTION_NODE :
336 {
337 ProcessingInstruction pi = (ProcessingInstruction) node;
338 String name = pi.getNodeName();
339
340 // String data = pi.getData();
341 if (name.equals("xslt-next-is-raw"))
342 {
343 nextIsRaw = true;
344 }
345 else
346 {
347 this.m_contentHandler.processingInstruction(pi.getNodeName(),
348 pi.getData());
349 }
350 }
351 break;
352 case Node.CDATA_SECTION_NODE :
353 {
361 }
362
363 dispatachChars(node);
364
365 {
366 if (isLexH)
367 {
368 lh.endCDATA();
369 }
370 }
371 }
372 break;
373 case Node.TEXT_NODE :
374 {
375 //String data = ((Text) node).getData();
376
377 if (nextIsRaw)
378 {
379 nextIsRaw = false;
380
381 m_contentHandler.processingInstruction(Result.PI_DISABLE_OUTPUT_ESCAPING, "");
382 dispatachChars(node);
383 m_contentHandler.processingInstruction(Result.PI_ENABLE_OUTPUT_ESCAPING, "");
384 }
385 else
386 {
387 dispatachChars(node);
388 }
389 }
390 break;
391 case Node.ENTITY_REFERENCE_NODE :
392 {
393 EntityReference eref = (EntityReference) node;
394
395 if (m_contentHandler instanceof LexicalHandler)
396 {
397 ((LexicalHandler) this.m_contentHandler).startEntity(
398 eref.getNodeName());
399 }
400 else
401 {
402
403 // warning("Can not output entity to a pure SAX ContentHandler");
408 }
409 }
410
411 /**
412 * End processing of given node
413 *
414 *
415 * @param node Node we just finished processing
416 *
417 * @throws org.xml.sax.SAXException
418 */
419 protected void endNode(Node node) throws org.xml.sax.SAXException
420 {
421
422 switch (node.getNodeType())
423 {
424 case Node.DOCUMENT_NODE :
425 break;
426
427 case Node.ELEMENT_NODE :
428 String ns = DOM2Helper.getNamespaceOfNode(node);
429 if(null == ns)
430 ns = "";
431 this.m_contentHandler.endElement(ns,
432 DOM2Helper.getLocalNameOfNode(node),
433 node.getNodeName());
434
435 if (m_Serializer == null) {
436 // Don't bother with endPrefixMapping calls if the ContentHandler is a
437 // SerializationHandler because SerializationHandler's ignore the
438 // endPrefixMapping() calls anyways. . . . This is an optimization.
439 Element elem_node = (Element) node;
440 NamedNodeMap atts = elem_node.getAttributes();
441 int nAttrs = atts.getLength();
442
443 // do the endPrefixMapping calls in reverse order
444 // of the startPrefixMapping calls
445 for (int i = (nAttrs-1); 0 <= i; i--)
446 {
447 final Node attr = atts.item(i);
448 final String attrName = attr.getNodeName();
449 final int colon = attrName.indexOf(':');
450 final String prefix;
451
452 if (attrName.equals("xmlns") || attrName.startsWith("xmlns:"))
|