KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > batik > dom > util > SAXDocumentFactory


1 /*
2
3    Copyright 2001-2003 The Apache Software Foundation
4
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    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 package org.apache.batik.dom.util;
19
20 import java.io.IOException JavaDoc;
21 import java.io.InputStream JavaDoc;
22 import java.io.InterruptedIOException JavaDoc;
23 import java.io.Reader JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.LinkedList JavaDoc;
26 import java.util.List JavaDoc;
27
28 import org.w3c.dom.DOMImplementation JavaDoc;
29 import org.w3c.dom.Document JavaDoc;
30 import org.w3c.dom.Element JavaDoc;
31 import org.w3c.dom.Node JavaDoc;
32
33 import org.xml.sax.Attributes JavaDoc;
34 import org.xml.sax.ErrorHandler JavaDoc;
35 import org.xml.sax.InputSource JavaDoc;
36 import org.xml.sax.Locator JavaDoc;
37 import org.xml.sax.SAXException JavaDoc;
38 import org.xml.sax.SAXParseException JavaDoc;
39 import org.xml.sax.XMLReader JavaDoc;
40 import org.xml.sax.ext.LexicalHandler JavaDoc;
41 import org.xml.sax.helpers.DefaultHandler JavaDoc;
42 import org.xml.sax.helpers.XMLReaderFactory JavaDoc;
43
44 import org.apache.batik.util.HaltingThread;
45
46 /**
47  * This class contains methods for creating Document instances
48  * from an URI using SAX2.
49  *
50  * @author <a HREF="mailto:stephane@hillion.org">Stephane Hillion</a>
51  * @version $Id: SAXDocumentFactory.java,v 1.29 2005/03/27 08:58:32 cam Exp $
52  */

53 public class SAXDocumentFactory
54     extends DefaultHandler JavaDoc
55     implements LexicalHandler JavaDoc,
56                DocumentFactory {
57
58     /**
59      * The DOM implementation used to create the document.
60      */

61     protected DOMImplementation JavaDoc implementation;
62
63     /**
64      * The SAX2 parser classname.
65      */

66     protected String JavaDoc parserClassName;
67
68     /**
69      * The created document.
70      */

71     protected Document JavaDoc document;
72     
73     /**
74      * The created document descriptor.
75      */

76     protected DocumentDescriptor documentDescriptor;
77
78     /**
79      * Whether a document descriptor must be generated.
80      */

81     protected boolean createDocumentDescriptor;
82
83     /**
84      * The current node.
85      */

86     protected Node JavaDoc currentNode;
87
88     /**
89      * The locator.
90      */

91     protected Locator JavaDoc locator;
92
93     /**
94      * Contains collected string data. May be Text, CDATA or Comment.
95      */

96     protected StringBuffer JavaDoc stringBuffer = new StringBuffer JavaDoc();
97     /**
98      * Indicates if stringBuffer has content, needed in case of
99      * zero sized "text" content.
100      */

101     protected boolean stringContent;
102
103     /**
104      * True if the parser is currently parsing a DTD.
105      */

106     protected boolean inDTD;
107
108     /**
109      * True if the parser is currently parsing a CDATA section.
110      */

111     protected boolean inCDATA;
112
113     /**
114      * Whether the parser is in validating mode.
115      */

116     protected boolean isValidating;
117
118     /**
119      * The stack used to store the namespace URIs.
120      */

121     protected HashTableStack namespaces;
122
123     /**
124      * The error handler.
125      */

126     protected ErrorHandler JavaDoc errorHandler;
127
128     protected interface PreInfo {
129         public Node JavaDoc createNode(Document JavaDoc doc);
130     }
131
132     static class ProcessingInstructionInfo implements PreInfo {
133         public String JavaDoc target, data;
134         public ProcessingInstructionInfo(String JavaDoc target, String JavaDoc data) {
135             this.target = target;
136             this.data = data;
137         }
138         public Node JavaDoc createNode(Document JavaDoc doc) {
139             return doc.createProcessingInstruction(target, data);
140         }
141     }
142
143     static class CommentInfo implements PreInfo {
144         public String JavaDoc comment;
145         public CommentInfo(String JavaDoc comment) {
146             this.comment = comment;
147         }
148         public Node JavaDoc createNode(Document JavaDoc doc) {
149             return doc.createComment(comment);
150         }
151     }
152
153     static class CDataInfo implements PreInfo {
154         public String JavaDoc cdata;
155         public CDataInfo(String JavaDoc cdata) {
156             this.cdata = cdata;
157         }
158         public Node JavaDoc createNode(Document JavaDoc doc) {
159             return doc.createCDATASection(cdata);
160         }
161     }
162
163     static class TextInfo implements PreInfo {
164         public String JavaDoc text;
165         public TextInfo(String JavaDoc text) {
166             this.text = text;
167         }
168         public Node JavaDoc createNode(Document JavaDoc doc) {
169             return doc.createTextNode(text);
170         }
171     }
172
173     /**
174      * Various elements encountered prior to real document root element.
175      * List of PreInfo objects.
176      */

177     protected List JavaDoc preInfo;
178
179     /**
180      * Creates a new SAXDocumentFactory object.
181      * No document descriptor will be created while generating a document.
182      * @param impl The DOM implementation to use for building the DOM tree.
183      * @param parser The SAX2 parser classname.
184      */

185     public SAXDocumentFactory(DOMImplementation JavaDoc impl,
186                               String JavaDoc parser) {
187     implementation = impl;
188     parserClassName = parser;
189     }
190
191     /**
192      * Creates a new SAXDocumentFactory object.
193      * @param impl The DOM implementation to use for building the DOM tree.
194      * @param parser The SAX2 parser classname.
195      * @param dd Whether a document descriptor must be generated.
196      */

197     public SAXDocumentFactory(DOMImplementation JavaDoc impl,
198                               String JavaDoc parser,
199                               boolean dd) {
200     implementation = impl;
201     parserClassName = parser;
202         createDocumentDescriptor = dd;
203     }
204
205     /**
206      * Creates a Document instance.
207      * @param ns The namespace URI of the root element of the document.
208      * @param root The name of the root element of the document.
209      * @param uri The document URI.
210      * @exception IOException if an error occured while reading the document.
211      */

212     public Document JavaDoc createDocument(String JavaDoc ns, String JavaDoc root, String JavaDoc uri)
213         throws IOException JavaDoc {
214         return createDocument(ns, root, uri, new InputSource JavaDoc(uri));
215     }
216
217     /**
218      * Creates a Document instance.
219      * @param uri The document URI.
220      * @exception IOException if an error occured while reading the document.
221      */

222     public Document JavaDoc createDocument(String JavaDoc uri)
223         throws IOException JavaDoc {
224         return createDocument(new InputSource JavaDoc(uri));
225     }
226
227     /**
228      * Creates a Document instance.
229      * @param ns The namespace URI of the root element of the document.
230      * @param root The name of the root element of the document.
231      * @param uri The document URI.
232      * @param is The document input stream.
233      * @exception IOException if an error occured while reading the document.
234      */

235     public Document JavaDoc createDocument(String JavaDoc ns, String JavaDoc root, String JavaDoc uri,
236                    InputStream JavaDoc is) throws IOException JavaDoc {
237         InputSource JavaDoc inp = new InputSource JavaDoc(is);
238         inp.setSystemId(uri);
239         return createDocument(ns, root, uri, inp);
240     }
241
242     /**
243      * Creates a Document instance.
244      * @param uri The document URI.
245      * @param is The document input stream.
246      * @exception IOException if an error occured while reading the document.
247      */

248     public Document JavaDoc createDocument(String JavaDoc uri, InputStream JavaDoc is)
249         throws IOException JavaDoc {
250         InputSource JavaDoc inp = new InputSource JavaDoc(is);
251         inp.setSystemId(uri);
252         return createDocument(inp);
253     }
254
255     /**
256      * Creates a Document instance.
257      * @param ns The namespace URI of the root element of the document.
258      * @param root The name of the root element of the document.
259      * @param uri The document URI.
260      * @param r The document reader.
261      * @exception IOException if an error occured while reading the document.
262      */

263     public Document JavaDoc createDocument(String JavaDoc ns, String JavaDoc root, String JavaDoc uri,
264                                    Reader JavaDoc r) throws IOException JavaDoc {
265         InputSource JavaDoc inp = new InputSource JavaDoc(r);
266         inp.setSystemId(uri);
267         return createDocument(ns, root, uri, inp);
268     }
269
270     /**
271      * Creates a Document instance.
272      * @param ns The namespace URI of the root element of the document.
273      * @param root The name of the root element of the document.
274      * @param uri The document URI.
275      * @param r an XMLReaderInstance
276      * @exception IOException if an error occured while reading the document.
277      */

278     public Document JavaDoc createDocument(String JavaDoc ns, String JavaDoc root, String JavaDoc uri,
279                                    XMLReader JavaDoc r) throws IOException JavaDoc {
280         r.setContentHandler(this);
281         r.setDTDHandler(this);
282         r.setEntityResolver(this);
283         try {
284             r.parse(uri);
285         } catch (SAXException JavaDoc e) {
286             Exception JavaDoc ex = e.getException();
287             if (ex != null && ex instanceof InterruptedIOException JavaDoc) {
288                 throw (InterruptedIOException JavaDoc) ex;
289             }
290             throw new IOException JavaDoc(e.getMessage());
291         }
292         currentNode = null;
293         Document JavaDoc ret = document;
294         document = null;
295         return ret;
296     }
297
298     /**
299      * Creates a Document instance.
300      * @param uri The document URI.
301      * @param r The document reader.
302      * @exception IOException if an error occured while reading the document.
303      */

304     public Document JavaDoc createDocument(String JavaDoc uri, Reader JavaDoc r) throws IOException JavaDoc {
305         InputSource JavaDoc inp = new InputSource JavaDoc(r);
306         inp.setSystemId(uri);
307         return createDocument(inp);
308     }
309
310     /**
311      * Creates a Document.
312      * @param ns The namespace URI of the root element.
313      * @param root The name of the root element.
314      * @param uri The document URI.
315      * @param is The document input source.
316      * @exception IOException if an error occured while reading the document.
317      */

318     protected Document JavaDoc createDocument(String JavaDoc ns, String JavaDoc root, String JavaDoc uri,
319                                       InputSource JavaDoc is)
320     throws IOException JavaDoc {
321         Document JavaDoc ret = createDocument(is);
322         Element JavaDoc docElem = ret.getDocumentElement();
323
324         String JavaDoc lname = root;
325         String JavaDoc nsURI = ns;
326         if (ns == null) {
327             int idx = lname.indexOf(':');
328             String JavaDoc nsp = (idx == -1 || idx == lname.length()-1)
329                 ? ""
330                 : lname.substring(0, idx);
331             nsURI = namespaces.get(nsp);
332             if (idx != -1 && idx != lname.length()-1) {
333                 lname = lname.substring(idx+1);
334             }
335         }
336
337
338         String JavaDoc docElemNS = docElem.getNamespaceURI();
339         if ((docElemNS != nsURI) &&
340             ((docElemNS == null) || (!docElemNS.equals(nsURI))))
341             throw new IOException JavaDoc
342                 ("Root element namespace does not match that requested:\n" +
343                  "Requested: " + nsURI + "\n" +
344                  "Found: " + docElemNS);
345
346         if (docElemNS != null) {
347             if (!docElem.getLocalName().equals(lname))
348                 throw new IOException JavaDoc
349                     ("Root element does not match that requested:\n" +
350                      "Requested: " + lname + "\n" +
351                      "Found: " + docElem.getLocalName());
352         } else {
353             if (!docElem.getNodeName().equals(lname))
354                 throw new IOException JavaDoc
355                     ("Root element does not match that requested:\n" +
356                      "Requested: " + lname + "\n" +
357                      "Found: " + docElem.getNodeName());
358         }
359
360         return ret;
361     }
362
363
364     /**
365      * Creates a Document.
366      * @param is The document input source.
367      * @exception IOException if an error occured while reading the document.
368      */

369     protected Document JavaDoc createDocument(InputSource JavaDoc is)
370     throws IOException JavaDoc {
371     try {
372             XMLReader JavaDoc parser =
373                 XMLReaderFactory.createXMLReader(parserClassName);
374
375             parser.setContentHandler(this);
376             parser.setDTDHandler(this);
377             parser.setEntityResolver(this);
378             parser.setErrorHandler((errorHandler == null) ?
379                                    this : errorHandler);
380
381             parser.setFeature("http://xml.org/sax/features/namespaces",
382                   true);
383             parser.setFeature("http://xml.org/sax/features/namespace-prefixes",
384                               true);
385         parser.setFeature("http://xml.org/sax/features/validation",
386                   isValidating);
387         parser.setProperty("http://xml.org/sax/properties/lexical-handler",
388                    this);
389             parser.parse(is);
390     } catch (SAXException JavaDoc e) {
391             Exception JavaDoc ex = e.getException();
392             if (ex != null && ex instanceof InterruptedIOException JavaDoc) {
393                 throw (InterruptedIOException JavaDoc)ex;
394             }
395             throw new IOException JavaDoc(e.getMessage());
396     }
397
398         currentNode = null;
399         Document JavaDoc ret = document;
400         document = null;
401         locator = null;
402     return ret;
403     }
404
405     /**
406      * Returns the document descriptor associated with the latest created
407      * document.
408      * @return null if no document or descriptor was previously generated.
409      */

410     public DocumentDescriptor getDocumentDescriptor() {
411         return documentDescriptor;
412     }
413
414     /**
415      * <b>SAX</b>: Implements {@link
416      * org.xml.sax.ContentHandler#setDocumentLocator(Locator)}.
417      */

418     public void setDocumentLocator(Locator JavaDoc l) {
419         locator = l;
420     }
421
422     /**
423      * Sets whether or not the XML parser will validate the XML document
424      * depending on the specified parameter.
425      *
426      * @param isValidating indicates that the XML parser will validate the XML
427      * document
428      */

429     public void setValidating(boolean isValidating) {
430     this.isValidating = isValidating;
431     }
432
433     /**
434      * Returns true if the XML parser validates the XML stream, false
435      * otherwise.
436      */

437     public boolean isValidating() {
438     return isValidating;
439     }
440
441     /**
442      * Sets a custom error handler.
443      */

444     public void setErrorHandler(ErrorHandler JavaDoc eh) {
445         errorHandler = eh;
446     }
447
448     public DOMImplementation JavaDoc getDOMImplementation(String JavaDoc ver) {
449         return implementation;
450     }
451
452     /**
453      * <b>SAX</b>: Implements {@link
454      * org.xml.sax.ErrorHandler#fatalError(SAXParseException)}.
455      */

456     public void fatalError(SAXParseException JavaDoc ex) throws SAXException JavaDoc {
457         throw ex;
458     }
459
460     /**
461      * <b>SAX</b>: Implements {@link
462      * org.xml.sax.ErrorHandler#error(SAXParseException)}.
463      */

464     public void error(SAXParseException JavaDoc ex) throws SAXException JavaDoc {
465     throw ex;
466     }
467
468     /**
469      * <b>SAX</b>: Implements {@link
470      * org.xml.sax.ErrorHandler#warning(SAXParseException)}.
471      */

472     public void warning(SAXParseException JavaDoc ex) throws SAXException JavaDoc {
473     }
474
475     /**
476      * <b>SAX</b>: Implements {@link
477      * org.xml.sax.ContentHandler#startDocument()}.
478      */

479     public void startDocument() throws SAXException JavaDoc {
480         preInfo = new LinkedList JavaDoc();
481         namespaces = new HashTableStack();
482     namespaces.put("xml", XMLSupport.XML_NAMESPACE_URI);
483     namespaces.put("xmlns", XMLSupport.XMLNS_NAMESPACE_URI);
484     namespaces.put("", null);
485
486         inDTD = false;
487         inCDATA = false;
488         currentNode = null;
489         document = null;
490
491         stringBuffer.setLength(0);
492         stringContent = false;
493
494         if (createDocumentDescriptor) {
495             documentDescriptor = new DocumentDescriptor();
496         } else {
497             documentDescriptor = null;
498         }
499     }
500
501     /**
502      * <b>SAX</b>: Implements {@link
503      * org.xml.sax.ContentHandler#startElement(String,String,String,Attributes)}.
504      */

505     public void startElement(String JavaDoc uri,
506                  String JavaDoc localName,
507                  String JavaDoc rawName,
508                  Attributes JavaDoc attributes) throws SAXException JavaDoc {
509         // Check If we should halt early.
510
if (HaltingThread.hasBeenHalted()) {
511             throw new SAXException JavaDoc(new InterruptedIOException JavaDoc());
512         }
513
514     // Namespaces resolution
515
int len = attributes.getLength();
516     namespaces.push();
517         String JavaDoc version = null;
518     for (int i = 0; i < len; i++) {
519         String JavaDoc aname = attributes.getQName(i);
520             int slen = aname.length();
521             if (slen < 5)
522                 continue;
523             if (aname.equals("version")) {
524                 version = attributes.getValue(i);
525                 continue;
526             }
527             if (!aname.startsWith("xmlns"))
528                 continue;
529             if (slen == 5) {
530                 String JavaDoc ns = attributes.getValue(i);
531                 if (ns.length() == 0)
532                     ns = null;
533         namespaces.put("", ns);
534         } else if (aname.charAt(5) == ':') {
535                 String JavaDoc ns = attributes.getValue(i);
536                 if (ns.length() == 0) {
537                     ns = null;
538                 }
539                 namespaces.put(aname.substring(6), ns);
540             }
541     }
542
543         // Add any collected String Data before element.
544
appendStringData();
545
546     // Element creation
547
Element JavaDoc e;
548     int idx = rawName.indexOf(':');
549     String JavaDoc nsp = (idx == -1 || idx == rawName.length()-1)
550         ? ""
551         : rawName.substring(0, idx);
552     String JavaDoc nsURI = namespaces.get(nsp);
553         if (currentNode == null) {
554             implementation = getDOMImplementation(version);
555             document = implementation.createDocument(nsURI, rawName, null);
556             Iterator JavaDoc i = preInfo.iterator();
557             currentNode = e = document.getDocumentElement();
558             while (i.hasNext()) {
559                 PreInfo pi = (PreInfo)i.next();
560                 Node JavaDoc n = pi.createNode(document);
561                 document.insertBefore(n, e);
562             }
563             preInfo = null;
564         } else {
565             e = document.createElementNS(nsURI, rawName);
566             currentNode.appendChild(e);
567             currentNode = e;
568         }
569
570         // Storage of the line number.
571
if (createDocumentDescriptor && locator != null) {
572             documentDescriptor.setLocationLine(e, locator.getLineNumber());
573         }
574
575     // Attributes creation
576
for (int i = 0; i < len; i++) {
577         String JavaDoc aname = attributes.getQName(i);
578         if (aname.equals("xmlns")) {
579         e.setAttributeNS(XMLSupport.XMLNS_NAMESPACE_URI,
580                  aname,
581                  attributes.getValue(i));
582         } else {
583         idx = aname.indexOf(':');
584         nsURI = (idx == -1)
585                     ? null
586                     : namespaces.get(aname.substring(0, idx));
587         e.setAttributeNS(nsURI, aname, attributes.getValue(i));
588         }
589     }
590     }
591
592     /**
593      * <b>SAX</b>: Implements {@link
594      * org.xml.sax.ContentHandler#endElement(String,String,String)}.
595      */

596     public void endElement(String JavaDoc uri, String JavaDoc localName, String JavaDoc rawName)
597     throws SAXException JavaDoc {
598         appendStringData(); // add string data if any.
599

600         if (currentNode != null)
601             currentNode = currentNode.getParentNode();
602     namespaces.pop();
603     }
604
605     public void appendStringData() {
606         if (!stringContent) return;
607
608         String JavaDoc str = stringBuffer.toString();
609         stringBuffer.setLength(0); // reuse buffer.
610
stringContent = false;
611         if (currentNode == null) {
612             if (inCDATA) preInfo.add(new CDataInfo(str));
613             else preInfo.add(new TextInfo(str));
614         } else {
615             Node JavaDoc n;
616             if (inCDATA) n = document.createCDATASection(str);
617             else n = document.createTextNode(str);
618             currentNode.appendChild(n);
619         }
620     }
621     
622     /**
623      * <b>SAX</b>: Implements {@link
624      * org.xml.sax.ContentHandler#characters(char[],int,int)}.
625      */

626     public void characters(char ch[], int start, int length)
627         throws SAXException JavaDoc {
628         stringBuffer.append(ch, start, length);
629         stringContent = true;
630     }
631
632
633     /**
634      * <b>SAX</b>: Implements {@link
635      * org.xml.sax.ContentHandler#ignorableWhitespace(char[],int,int)}.
636      */

637     public void ignorableWhitespace(char[] ch,
638                                     int start,
639                                     int length)
640         throws SAXException JavaDoc {
641         stringBuffer.append(ch, start, length);
642         stringContent = true;
643     }
644
645     /**
646      * <b>SAX</b>: Implements {@link
647      * org.xml.sax.ContentHandler#processingInstruction(String,String)}.
648      */

649     public void processingInstruction(String JavaDoc target, String JavaDoc data)
650         throws SAXException JavaDoc {
651     if (inDTD)
652             return;
653         
654         appendStringData(); // Add any collected String Data before PI
655

656         if (currentNode == null)
657             preInfo.add(new ProcessingInstructionInfo(target, data));
658         else
659             currentNode.appendChild
660                 (document.createProcessingInstruction(target, data));
661     }
662
663     // LexicalHandler /////////////////////////////////////////////////////////
664

665     /**
666      * <b>SAX</b>: Implements {@link
667      * org.xml.sax.ext.LexicalHandler#startDTD(String,String,String)}.
668      */

669     public void startDTD(String JavaDoc name, String JavaDoc publicId, String JavaDoc systemId)
670     throws SAXException JavaDoc {
671         appendStringData(); // Add collected string data before entering DTD
672
inDTD = true;
673     }
674
675     /**
676      * <b>SAX</b>: Implements {@link org.xml.sax.ext.LexicalHandler#endDTD()}.
677      */

678     public void endDTD() throws SAXException JavaDoc {
679     inDTD = false;
680     }
681
682     /**
683      * <b>SAX</b>: Implements
684      * {@link org.xml.sax.ext.LexicalHandler#startEntity(String)}.
685      */

686     public void startEntity(String JavaDoc name) throws SAXException JavaDoc {
687     }
688
689     /**
690      * <b>SAX</b>: Implements
691      * {@link org.xml.sax.ext.LexicalHandler#endEntity(String)}.
692      */

693     public void endEntity(String JavaDoc name) throws SAXException JavaDoc {
694     }
695
696     /**
697      * <b>SAX</b>: Implements {@link
698      * org.xml.sax.ext.LexicalHandler#startCDATA()}.
699      */

700     public void startCDATA() throws SAXException JavaDoc {
701         appendStringData(); // Add any collected String Data before CData
702
inCDATA = true;
703         stringContent = true; // always create CDATA even if empty.
704
}
705
706     /**
707      * <b>SAX</b>: Implements {@link
708      * org.xml.sax.ext.LexicalHandler#endCDATA()}.
709      */

710     public void endCDATA() throws SAXException JavaDoc {
711         appendStringData(); // Add the CDATA section
712
inCDATA = false;
713     }
714
715     /**
716      * <b>SAX</b>: Implements
717      * {@link org.xml.sax.ext.LexicalHandler#comment(char[],int,int)}.
718      */

719     public void comment(char ch[], int start, int length) throws SAXException JavaDoc {
720     if (inDTD) return;
721         appendStringData();
722
723         String JavaDoc str = new String JavaDoc(ch, start, length);
724         if (currentNode == null) {
725             preInfo.add(new CommentInfo(str));
726         } else {
727             currentNode.appendChild(document.createComment(str));
728         }
729     }
730 }
731
Popular Tags