KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > nu > xom > converters > SAXConverter


1 /* Copyright 2002-2004 Elliotte Rusty Harold
2    
3    This library is free software; you can redistribute it and/or modify
4    it under the terms of version 2.1 of the GNU Lesser General Public
5    License as published by the Free Software Foundation.
6    
7    This library is distributed in the hope that it will be useful,
8    but WITHOUT ANY WARRANTY; without even the implied warranty of
9    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10    GNU Lesser General Public License for more details.
11    
12    You should have received a copy of the GNU Lesser General Public
13    License along with this library; if not, write to the
14    Free Software Foundation, Inc., 59 Temple Place, Suite 330,
15    Boston, MA 02111-1307 USA
16    
17    You can contact Elliotte Rusty Harold by sending e-mail to
18    elharo@metalab.unc.edu. Please include the word "XOM" in the
19    subject line. The XOM home page is located at http://www.xom.nu/
20 */

21
22 package nu.xom.converters;
23
24 import nu.xom.Attribute;
25 import nu.xom.Comment;
26 import nu.xom.DocType;
27 import nu.xom.Document;
28 import nu.xom.Element;
29 import nu.xom.Node;
30 import nu.xom.Nodes;
31 import nu.xom.ParentNode;
32 import nu.xom.ProcessingInstruction;
33 import nu.xom.Text;
34
35 import org.xml.sax.ContentHandler JavaDoc;
36 import org.xml.sax.SAXException JavaDoc;
37 import org.xml.sax.ext.LexicalHandler JavaDoc;
38 import org.xml.sax.helpers.AttributesImpl JavaDoc;
39 import org.xml.sax.helpers.LocatorImpl JavaDoc;
40
41 /**
42  * <p>
43  * Feeds a XOM <code>Document</code> into a
44  * SAX2 <code>ContentHandler</code>.
45  * </p>
46  *
47  * @author Elliotte Rusty Harold
48  * @version 1.0
49  */

50 public class SAXConverter {
51
52     
53     private ContentHandler JavaDoc contentHandler;
54     private LexicalHandler JavaDoc lexicalHandler;
55     private LocatorImpl JavaDoc locator;
56
57     
58     /**
59      * <p>
60      * Creates a new <code>SAXConverter</code>.
61      * </p>
62      *
63      * @param handler the SAX2 content handler
64      * that receives the data
65      *
66      * @throws NullPointerException if handler is null
67      *
68      */

69     public SAXConverter(ContentHandler JavaDoc handler) {
70         setContentHandler(handler);
71     }
72
73     
74     /**
75      * <p>
76      * Set the content handler for this converter.
77      * </p>
78      *
79      * @param handler SAX2 content handler that
80      * receives the data
81      *
82      * @throws NullPointerException if handler is null
83      *
84      */

85     public void setContentHandler(ContentHandler JavaDoc handler) {
86         
87         if (handler == null) {
88             throw new NullPointerException JavaDoc(
89               "ContentHandler must be non-null."
90             );
91         }
92         this.contentHandler = handler;
93         
94     }
95
96     
97     /**
98      * <p>
99      * Returns the content handler.
100      * </p>
101      *
102      * @return SAX2 content handler that receives the data
103      */

104     public ContentHandler JavaDoc getContentHandler() {
105         return this.contentHandler;
106     }
107
108
109     /**
110      * <p>
111      * Sets the optional lexical handler for this converter.
112      * The only lexical events the converter supplies
113      * are comments.
114      * </p>
115      *
116      * @param handler the lexical handler;
117      * may be null to turn off lexical events
118      */

119     public void setLexicalHandler(LexicalHandler JavaDoc handler) {
120         this.lexicalHandler = handler;
121     }
122
123     
124     /**
125      * <p>
126      * Returns the <code>LexicalHandler</code> for this
127      * converter. This is only used for comments.
128      * </p>
129      *
130      * @return SAX2 lexical handler that receives
131      * lexical events
132      */

133     public LexicalHandler JavaDoc getLexicalHandler() {
134         return this.lexicalHandler;
135     }
136     
137     
138     // Not necessary to worry about parser exceptions passed to
139
// fatalError() because we're starting with a known good document.
140
// Only exceptions that can arise are thrown by
141
// the supplied ContentHandler, and we don't want to pass those
142
// to the ErrorHandler, or call endDocument() if such an exception
143
// is thrown
144
/**
145      * <p>
146      * Feed a document through this converter.
147      * </p>
148      *
149      * @param doc the document to pass to SAX
150      *
151      * @throws SAXException if the content handler
152      * or lexical handler throws an exception
153      */

154     public void convert(Document doc) throws SAXException JavaDoc {
155         
156         locator = new LocatorImpl JavaDoc();
157         locator.setSystemId(doc.getBaseURI());
158         contentHandler.setDocumentLocator(locator);
159         contentHandler.startDocument();
160         for (int i = 0; i < doc.getChildCount(); i++) {
161              process(doc.getChild(i));
162         }
163         contentHandler.endDocument();
164         
165     }
166     
167     
168     private void process(Node node) throws SAXException JavaDoc {
169         
170         if (node instanceof Element) {
171             convertElement((Element) node);
172         }
173         else if (node instanceof Text) {
174             String JavaDoc data = node.getValue();
175             contentHandler.characters(
176               data.toCharArray(), 0, data.length());
177         }
178         else if (node instanceof ProcessingInstruction) {
179             ProcessingInstruction instruction
180               = (ProcessingInstruction) node;
181             contentHandler.processingInstruction(
182               instruction.getTarget(), instruction.getValue());
183         }
184         else if (node instanceof Comment && lexicalHandler != null) {
185             String JavaDoc data = node.getValue();
186             lexicalHandler.comment(
187               data.toCharArray(), 0, data.length());
188         }
189         else if (node instanceof DocType && lexicalHandler != null) {
190             DocType type = (DocType) node;
191             lexicalHandler.startDTD(type.getRootElementName(),
192               type.getPublicID(), type.getSystemID());
193             lexicalHandler.endDTD();
194         }
195         
196     }
197     
198     
199     private void convertNamespace(Element element, String JavaDoc prefix)
200       throws SAXException JavaDoc {
201         
202         String JavaDoc uri = element.getNamespaceURI(prefix);
203         ParentNode parentNode = element.getParent();
204         Element parent = null;
205         if (parentNode instanceof Element) {
206             parent = (Element) parentNode;
207         }
208         
209         if (parent != null && uri.equals(parent.getNamespaceURI(prefix))) {
210             return;
211         }
212         else if (parent == null && "".equals(uri)) {
213             // Do not fire startPrefixMapping event for no namespace
214
// on root element
215
return;
216         }
217         contentHandler.startPrefixMapping(prefix, element.getNamespaceURI(prefix));
218         
219     }
220
221     
222     private void convertElement(Element element) throws SAXException JavaDoc {
223         
224         locator.setSystemId(element.getBaseURI());
225         
226         ParentNode parentNode = element.getParent();
227         Element parent = null;
228         if (parentNode instanceof Element) {
229             parent = (Element) parentNode;
230         }
231         
232         // start prefix mapping
233
for (int i = 0;
234              i < element.getNamespaceDeclarationCount();
235              i++) {
236             String JavaDoc prefix = element.getNamespacePrefix(i);
237             convertNamespace(element, prefix);
238         }
239         if (parent != null) {
240             // now handle element's prefix if not declared on ancestor
241
String JavaDoc prefix = element.getNamespacePrefix();
242             if (!element.getNamespaceURI(prefix)
243               .equals(parent.getNamespaceURI(prefix))) {
244                 contentHandler.startPrefixMapping(prefix,
245                   element.getNamespaceURI(prefix));
246             }
247             
248             // Handle attributes' prefixes if not declared on ancestor
249
for (int i = 0; i < element.getAttributeCount(); i++) {
250                 Attribute att = element.getAttribute(i);
251                 String JavaDoc attPrefix = att.getNamespacePrefix();
252                 if (!element.getNamespaceURI(attPrefix)
253                   .equals(parent.getNamespaceURI(attPrefix))
254                   && !element.getNamespacePrefix()
255                   .equals(attPrefix)
256                   // SAX never calls startPrefixMapping for the xml prefix
257
&& !"xml".equals(attPrefix)) {
258                     contentHandler.startPrefixMapping(attPrefix,
259                       element.getNamespaceURI(attPrefix));
260                 }
261             }
262         }
263         else { // declare all prefixes
264
String JavaDoc prefix = element.getNamespacePrefix();
265             if (!prefix.equals("") && !"xml".equals(prefix)) {
266                 contentHandler.startPrefixMapping(prefix,
267                   element.getNamespaceURI());
268             }
269             
270             // Handle attributes' prefixes if not declared on ancestor
271
for (int i = 0; i < element.getAttributeCount(); i++) {
272                 Attribute att = element.getAttribute(i);
273                 String JavaDoc attPrefix = att.getNamespacePrefix();
274                 if ("xml".equals(attPrefix)) {
275                     continue;
276                 }
277                 else if (!attPrefix.equals("") &&
278                   !attPrefix.equals(element.getNamespacePrefix())){
279                     contentHandler.startPrefixMapping(attPrefix,
280                       att.getNamespaceURI());
281                 }
282             }
283             
284         }
285         
286         
287         // add attributes
288
AttributesImpl JavaDoc saxAttributes = new AttributesImpl JavaDoc();
289         for (int i = 0; i < element.getAttributeCount(); i++) {
290             Attribute attribute = element.getAttribute(i);
291             // The base URIs provided by the locator have already
292
// accounted for any xml:base attributes. We do not
293
// also pass in xml:base attributes or some relative base
294
// URIs could be applied twice.
295
if ("base".equals(attribute.getLocalName())
296               && "http://www.w3.org/XML/1998/namespace".equals(attribute.getNamespaceURI())) {
297                 continue;
298             }
299             saxAttributes.addAttribute(attribute.getNamespaceURI(),
300               attribute.getLocalName(),
301               attribute.getQualifiedName(),
302               getSAXType(attribute),
303               attribute.getValue());
304         }
305         
306         
307         contentHandler.startElement(
308           element.getNamespaceURI(),
309           element.getLocalName(),
310           element.getQualifiedName(),
311           saxAttributes);
312         for (int i = 0; i < element.getChildCount(); i++) {
313             process(element.getChild(i));
314         }
315         contentHandler.endElement(element.getNamespaceURI(),
316           element.getLocalName(), element.getQualifiedName());
317         
318         // end prefix mappings
319
for (int i = 0;
320              i < element.getNamespaceDeclarationCount();
321              i++) {
322             String JavaDoc prefix = element.getNamespacePrefix(i);
323             if (parent == null) {
324                 String JavaDoc uri = element.getNamespaceURI(prefix);
325                 if ("".equals(uri)) continue;
326             }
327             contentHandler.endPrefixMapping(prefix);
328         }
329         if (parent != null) {
330             // Now handle element's prefix if not declared on ancestor
331
String JavaDoc prefix = element.getNamespacePrefix();
332             if (!element.getNamespaceURI(prefix)
333               .equals(parent.getNamespaceURI(prefix))) {
334                 contentHandler.endPrefixMapping(prefix);
335             }
336             
337             // Handle attributes' prefixes if not declared on ancestor
338
for (int i = 0; i < element.getAttributeCount(); i++) {
339                 Attribute att = element.getAttribute(i);
340                 String JavaDoc attPrefix = att.getNamespacePrefix();
341                 if (!element.getNamespaceURI(attPrefix)
342                   .equals(parent.getNamespaceURI(attPrefix))
343                   && !element.getNamespacePrefix().equals(
344                   attPrefix)
345                   && !"xml".equals(attPrefix)) {
346                     contentHandler.endPrefixMapping(attPrefix);
347                 }
348             }
349         }
350         else { // undeclare all prefixes
351
String JavaDoc prefix = element.getNamespacePrefix();
352             if (!prefix.equals("") && !"xml".equals(prefix)) {
353                 contentHandler.endPrefixMapping(prefix);
354             }
355             
356             // Handle attributes' prefixes if not declared on ancestor
357
for (int i = 0; i < element.getAttributeCount(); i++) {
358                 Attribute att = element.getAttribute(i);
359                 String JavaDoc attPrefix = att.getNamespacePrefix();
360                 if (!attPrefix.equals("") && !attPrefix
361                   .equals(element.getNamespacePrefix())
362                   && !"xml".equals(attPrefix)) {
363                     contentHandler.endPrefixMapping(attPrefix);
364                 }
365             }
366             
367         }
368     }
369     
370     
371     private static String JavaDoc getSAXType(Attribute attribute) {
372
373         Attribute.Type type = attribute.getType();
374         if (type.equals(Attribute.Type.UNDECLARED)) return "CDATA";
375         if (type.equals(Attribute.Type.CDATA)) return "CDATA";
376         if (type.equals(Attribute.Type.ID)) return "ID";
377         if (type.equals(Attribute.Type.IDREF)) return "IDREF";
378         if (type.equals(Attribute.Type.IDREFS)) return "IDREFS";
379         if (type.equals(Attribute.Type.NMTOKEN)) return "NMTOKEN";
380         if (type.equals(Attribute.Type.NMTOKENS)) return "NMTOKENS";
381         if (type.equals(Attribute.Type.ENTITY)) return "ENTITY";
382         if (type.equals(Attribute.Type.ENTITIES)) return "ENTITIES";
383         if (type.equals(Attribute.Type.NOTATION)) return "NOTATION";
384         return "NMTOKEN"; // ENUMERATED
385

386     }
387
388
389     /**
390      * <p>
391      * Converts a <code>Nodes</code> list into SAX by firing events
392      * into the registered handlers. This method calls
393      * invokes <code>startDocument</code> before processing the list
394      * of nodes, and calls <code>endDocument</code> after processing
395      * all of them.
396      * </p>
397      *
398      * @param nodes the nodes to pass to SAX
399      *
400      * @throws SAXException if the content handler
401      * or lexical handler throws an exception
402      */

403     public void convert(Nodes nodes) throws SAXException JavaDoc {
404         
405         if (nodes.size() == 1 && nodes.get(0) instanceof Document) {
406             convert((Document) nodes.get(0));
407         }
408         else {
409             locator = new LocatorImpl JavaDoc();
410             contentHandler.setDocumentLocator(locator);
411             contentHandler.startDocument();
412             for (int i = 0; i < nodes.size(); i++) {
413                 process(nodes.get(i));
414             }
415             contentHandler.endDocument();
416         }
417         
418     }
419
420     
421 }
422
Popular Tags