KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > fop > util > DOM2SAX


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 /* $Id$ */
19
20 package org.apache.fop.util;
21
22 import java.util.List JavaDoc;
23 import java.util.Map JavaDoc;
24 import java.util.Stack JavaDoc;
25
26 import org.w3c.dom.Document JavaDoc;
27 import org.w3c.dom.NamedNodeMap JavaDoc;
28 import org.w3c.dom.Node JavaDoc;
29
30 import org.xml.sax.ContentHandler JavaDoc;
31 import org.xml.sax.SAXException JavaDoc;
32 import org.xml.sax.ext.LexicalHandler JavaDoc;
33 import org.xml.sax.helpers.AttributesImpl JavaDoc;
34
35 /**
36  * Helper class that produces a SAX stream from a DOM Document.
37  * <p>
38  * Part of the code here copied and adapted from Apache Xalan-J,
39  * src/org/apache/xalan/xsltc/trax/DOM2SAX.java
40  */

41 public class DOM2SAX {
42
43     private static final String JavaDoc EMPTYSTRING = "";
44     private static final String JavaDoc XMLNS_PREFIX = "xmlns";
45
46     private ContentHandler JavaDoc contentHandler;
47     private LexicalHandler JavaDoc lexicalHandler;
48     
49     private Map JavaDoc prefixes = new java.util.HashMap JavaDoc();
50     
51     /**
52      * Main constructor
53      * @param handler the ContentHandler to send SAX events to
54      */

55     public DOM2SAX(ContentHandler JavaDoc handler) {
56         this.contentHandler = handler;
57         if (handler instanceof LexicalHandler JavaDoc) {
58             this.lexicalHandler = (LexicalHandler JavaDoc)handler;
59         }
60     }
61     
62     /**
63      * Writes the given document using the given ContentHandler.
64      * @param doc DOM document
65      * @param fragment if false no startDocument() and endDocument() calls are issued.
66      * @throws SAXException In case of a problem while writing XML
67      */

68     public void writeDocument(Document JavaDoc doc, boolean fragment) throws SAXException JavaDoc {
69         if (!fragment) {
70             contentHandler.startDocument();
71         }
72         for (Node JavaDoc n = doc.getFirstChild(); n != null;
73                 n = n.getNextSibling()) {
74             writeNode(n);
75         }
76         if (!fragment) {
77             contentHandler.endDocument();
78         }
79     }
80
81     /**
82      * Begin the scope of namespace prefix. Forward the event to the SAX handler
83      * only if the prefix is unknown or it is mapped to a different URI.
84      */

85     private boolean startPrefixMapping(String JavaDoc prefix, String JavaDoc uri)
86             throws SAXException JavaDoc {
87         boolean pushed = true;
88         Stack JavaDoc uriStack = (Stack JavaDoc)prefixes.get(prefix);
89
90         if (uriStack != null) {
91             if (uriStack.isEmpty()) {
92                 contentHandler.startPrefixMapping(prefix, uri);
93                 uriStack.push(uri);
94             } else {
95                 final String JavaDoc lastUri = (String JavaDoc) uriStack.peek();
96                 if (!lastUri.equals(uri)) {
97                     contentHandler.startPrefixMapping(prefix, uri);
98                     uriStack.push(uri);
99                 } else {
100                     pushed = false;
101                 }
102             }
103         } else {
104             contentHandler.startPrefixMapping(prefix, uri);
105             uriStack = new Stack JavaDoc();
106             prefixes.put(prefix, uriStack);
107             uriStack.push(uri);
108         }
109         return pushed;
110     }
111
112     /*
113      * End the scope of a name prefix by popping it from the stack and passing
114      * the event to the SAX Handler.
115      */

116     private void endPrefixMapping(String JavaDoc prefix) throws SAXException JavaDoc {
117         final Stack JavaDoc uriStack = (Stack JavaDoc)prefixes.get(prefix);
118
119         if (uriStack != null) {
120             contentHandler.endPrefixMapping(prefix);
121             uriStack.pop();
122         }
123     }
124
125     /**
126      * If the DOM was created using a DOM 1.0 API, the local name may be null.
127      * If so, get the local name from the qualified name before generating the
128      * SAX event.
129      */

130     private static String JavaDoc getLocalName(Node JavaDoc node) {
131         final String JavaDoc localName = node.getLocalName();
132
133         if (localName == null) {
134             final String JavaDoc qname = node.getNodeName();
135             final int col = qname.lastIndexOf(':');
136             return (col > 0) ? qname.substring(col + 1) : qname;
137         }
138         return localName;
139     }
140
141     /**
142      * Writes a node using the given writer.
143      * @param node node to serialize
144      * @throws SAXException In case of a problem while writing XML
145      */

146     private void writeNode(Node JavaDoc node)
147                 throws SAXException JavaDoc {
148         if (node == null) {
149             return;
150         }
151
152         switch (node.getNodeType()) {
153         case Node.ATTRIBUTE_NODE: // handled by ELEMENT_NODE
154
case Node.DOCUMENT_FRAGMENT_NODE:
155         case Node.DOCUMENT_TYPE_NODE:
156         case Node.ENTITY_NODE:
157         case Node.ENTITY_REFERENCE_NODE:
158         case Node.NOTATION_NODE:
159             // These node types are ignored!!!
160
break;
161         case Node.CDATA_SECTION_NODE:
162             final String JavaDoc cdata = node.getNodeValue();
163             if (lexicalHandler != null) {
164                 lexicalHandler.startCDATA();
165                 contentHandler.characters(cdata.toCharArray(), 0, cdata.length());
166                 lexicalHandler.endCDATA();
167             } else {
168                 // in the case where there is no lex handler, we still
169
// want the text of the cdate to make its way through.
170
contentHandler.characters(cdata.toCharArray(), 0, cdata.length());
171             }
172             break;
173
174         case Node.COMMENT_NODE: // should be handled!!!
175
if (lexicalHandler != null) {
176                 final String JavaDoc value = node.getNodeValue();
177                 lexicalHandler.comment(value.toCharArray(), 0, value.length());
178             }
179             break;
180         case Node.DOCUMENT_NODE:
181             contentHandler.startDocument();
182             Node JavaDoc next = node.getFirstChild();
183             while (next != null) {
184                 writeNode(next);
185                 next = next.getNextSibling();
186             }
187             contentHandler.endDocument();
188             break;
189
190         case Node.ELEMENT_NODE:
191             String JavaDoc prefix;
192             List JavaDoc pushedPrefixes = new java.util.ArrayList JavaDoc();
193             final AttributesImpl JavaDoc attrs = new AttributesImpl JavaDoc();
194             final NamedNodeMap JavaDoc map = node.getAttributes();
195             final int length = map.getLength();
196
197             // Process all namespace declarations
198
for (int i = 0; i < length; i++) {
199                 final Node JavaDoc attr = map.item(i);
200                 final String JavaDoc qnameAttr = attr.getNodeName();
201
202                 // Ignore everything but NS declarations here
203
if (qnameAttr.startsWith(XMLNS_PREFIX)) {
204                     final String JavaDoc uriAttr = attr.getNodeValue();
205                     final int colon = qnameAttr.lastIndexOf(':');
206                     prefix = (colon > 0) ? qnameAttr.substring(colon + 1)
207                             : EMPTYSTRING;
208                     if (startPrefixMapping(prefix, uriAttr)) {
209                         pushedPrefixes.add(prefix);
210                     }
211                 }
212             }
213
214             // Process all other attributes
215
for (int i = 0; i < length; i++) {
216                 final Node JavaDoc attr = map.item(i);
217                 final String JavaDoc qnameAttr = attr.getNodeName();
218
219                 // Ignore NS declarations here
220
if (!qnameAttr.startsWith(XMLNS_PREFIX)) {
221                     final String JavaDoc uriAttr = attr.getNamespaceURI();
222
223                     // Uri may be implicitly declared
224
if (uriAttr != null) {
225                         final int colon = qnameAttr.lastIndexOf(':');
226                         prefix = (colon > 0) ? qnameAttr.substring(0, colon)
227                                 : EMPTYSTRING;
228                         if (startPrefixMapping(prefix, uriAttr)) {
229                             pushedPrefixes.add(prefix);
230                         }
231                     }
232
233                     // Add attribute to list
234
attrs.addAttribute(attr.getNamespaceURI(),
235                             getLocalName(attr), qnameAttr, "CDATA", attr
236                                     .getNodeValue());
237                 }
238             }
239
240             // Now process the element itself
241
final String JavaDoc qname = node.getNodeName();
242             final String JavaDoc uri = node.getNamespaceURI();
243             final String JavaDoc localName = getLocalName(node);
244
245             // Uri may be implicitly declared
246
if (uri != null) {
247                 final int colon = qname.lastIndexOf(':');
248                 prefix = (colon > 0) ? qname.substring(0, colon) : EMPTYSTRING;
249                 if (startPrefixMapping(prefix, uri)) {
250                     pushedPrefixes.add(prefix);
251                 }
252             }
253
254             // Generate SAX event to start element
255
contentHandler.startElement(uri, localName, qname, attrs);
256
257             // Traverse all child nodes of the element (if any)
258
next = node.getFirstChild();
259             while (next != null) {
260                 writeNode(next);
261                 next = next.getNextSibling();
262             }
263
264             // Generate SAX event to close element
265
contentHandler.endElement(uri, localName, qname);
266
267             // Generate endPrefixMapping() for all pushed prefixes
268
final int nPushedPrefixes = pushedPrefixes.size();
269             for (int i = 0; i < nPushedPrefixes; i++) {
270                 endPrefixMapping((String JavaDoc)pushedPrefixes.get(i));
271             }
272             break;
273
274         case Node.PROCESSING_INSTRUCTION_NODE:
275             contentHandler.processingInstruction(node.getNodeName(), node.getNodeValue());
276             break;
277
278         case Node.TEXT_NODE:
279             final String JavaDoc data = node.getNodeValue();
280             contentHandler.characters(data.toCharArray(), 0, data.length());
281             break;
282         default:
283             //nop
284
}
285     }
286
287     
288 }
289
Popular Tags