KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > icl > saxon > DOMDriver


1 package com.icl.saxon;
2 import com.icl.saxon.om.*;
3 import com.icl.saxon.tree.TreeBuilder;
4
5 import org.xml.sax.*;
6 import org.xml.sax.ext.LexicalHandler JavaDoc;
7 import org.xml.sax.helpers.AttributesImpl JavaDoc;
8 import org.xml.sax.helpers.NamespaceSupport JavaDoc;
9 import org.xml.sax.helpers.DefaultHandler JavaDoc;
10
11 import java.util.Enumeration JavaDoc;
12 import java.util.Locale JavaDoc;
13 import java.util.Hashtable JavaDoc;
14
15 import org.w3c.dom.*;
16
17 /**
18 * DOMDriver.java: (pseudo-)SAX driver for DOM.<BR>
19 * This class simulates the action of a SAX Parser, taking an already-constructed
20 * DOM Document and walking around it in a depth-first traversal,
21 * calling a SAX-compliant ContentHandler to process the children as it does so.
22 * @author MHK, 5 Jun 1998
23 * @version 20 Jan 1999 modified to use AttributeListWrapper class
24 * @version 3 February 2000 modified to use AttributeCollection class
25 * @version 24 February 2000 modified to drive SAX2, which means it has to do namespace handling
26 */

27
28 public class DOMDriver implements Locator, XMLReader
29 {
30
31     protected ContentHandler contentHandler = new DefaultHandler JavaDoc();
32     private LexicalHandler JavaDoc lexicalHandler = null;
33     private NamespaceSupport JavaDoc nsSupport = new NamespaceSupport JavaDoc();
34     private AttributesImpl JavaDoc attlist = new AttributesImpl JavaDoc();
35     private String JavaDoc[] parts = new String JavaDoc[3];
36     private String JavaDoc[] elparts = new String JavaDoc[3];
37     private Hashtable JavaDoc nsDeclarations = new Hashtable JavaDoc();
38     protected Node root = null;
39     protected String JavaDoc systemId;
40     
41     /**
42     * Set the content handler.
43     * @param handler The object to receive content events. If this also implements LexicalHandler,
44     * it will also be notified of comments.
45     */

46     
47     public void setContentHandler (ContentHandler handler)
48     {
49         this.contentHandler = handler;
50         if (handler instanceof LexicalHandler JavaDoc) {
51             lexicalHandler = (LexicalHandler JavaDoc)handler;
52         }
53     }
54
55     public ContentHandler getContentHandler() {
56         return contentHandler;
57     }
58
59     /**
60     * <b>SAX1</b>: Sets the locale used for diagnostics; currently,
61     * only locales using the English language are supported.
62     * @param locale The locale for which diagnostics will be generated
63     */

64     
65     public void setLocale (Locale JavaDoc locale) throws SAXException
66     {}
67
68
69     /**
70      * <b>SAX2</b>: Returns the object used when resolving external
71      * entities during parsing (both general and parameter entities).
72      */

73      
74     public EntityResolver getEntityResolver ()
75     {
76         return null;
77     }
78
79     /**
80      * <b>SAX1, SAX2</b>: Set the entity resolver for this parser.
81      * @param handler The object to receive entity events.
82      */

83      
84     public void setEntityResolver (EntityResolver resolver) {}
85
86
87     /**
88      * <b>SAX2</b>: Returns the object used to process declarations related
89      * to notations and unparsed entities.
90      */

91      
92     public DTDHandler getDTDHandler () {
93         return null;
94     }
95
96     /**
97      * <b>SAX1, SAX2</b>: Set the DTD handler for this parser.
98      * @param handler The object to receive DTD events.
99      */

100     public void setDTDHandler (DTDHandler handler) {}
101
102
103     /**
104      * <b>SAX1</b>: Set the document handler for this parser. If a
105      * content handler was set, this document handler will supplant it.
106      * The parser is set to report all XML 1.0 names rather than to
107      * filter out "xmlns" attributes (the "namespace-prefixes" feature
108      * is set to true).
109      *
110      * @deprecated SAX2 programs should use the XMLReader interface
111      * and a ContentHandler.
112      *
113      * @param handler The object to receive document events.
114      */

115      
116     public void setDocumentHandler (DocumentHandler handler) {}
117
118     /**
119      * <b>SAX1, SAX2</b>: Set the error handler for this parser.
120      * @param handler The object to receive error events.
121      */

122      
123     public void setErrorHandler (ErrorHandler handler) {}
124
125     /**
126      * <b>SAX2</b>: Returns the object used to receive callbacks for XML
127      * errors of all levels (fatal, nonfatal, warning); this is never null;
128      */

129      
130     public ErrorHandler getErrorHandler () { return null; }
131
132
133     /**
134     * Set the DOM Document that will be walked
135     */

136
137     // Note, although the code is written to allow starting at any node, and copying a subtree,
138
// this logic is never invoked. In practice, the whole document is always copied.
139

140     public void setStartNode(Node start) {
141         root = start;
142     }
143
144     /**
145     * Parse from InputSource.
146     * The InputSource is ignored; it's there only to satisfy the XMLReader interface
147     */

148
149     public void parse(InputSource source) throws SAXException {
150         parse();
151     };
152
153     /**
154     * Parse from SystemId.
155     * The SystemId is ignored; it's there only to satisfy the XMLReader interface
156     */

157
158     public void parse(String JavaDoc source) throws SAXException {
159         parse();
160     };
161
162     /**
163     * Walk a document (traversing the nodes depth first)
164     * @param doc The (DOM) Document object to walk.
165     * @exception SAXException On any error in the document
166     */

167
168     public void parse() throws SAXException
169     {
170         if (root==null) {
171             throw new SAXException("DOMDriver: no start node defined");
172         }
173         if (contentHandler==null) {
174             throw new SAXException("DOMDriver: no content handler defined");
175         }
176
177         contentHandler.setDocumentLocator(this);
178         contentHandler.startDocument();
179         if (root instanceof Element) {
180             sendElement((Element)root);
181         } else {
182             walkNode(root); // walk the root node
183
}
184         contentHandler.endDocument();
185     }
186
187     /**
188      * Walk a document starting from a particular element node. This has to make
189      * sure that all the namespace declarations in scope for the element are
190      * treated as if they were namespace declarations on the element itself.
191      */

192
193     private void sendElement(Element startNode) throws SAXException {
194         Element node = startNode;
195         NamedNodeMap topAtts = gatherNamespaces(node, false);
196         while (true) {
197             gatherNamespaces(node, true);
198             Node parent = node.getParentNode();
199             if (parent instanceof Element) {
200                 node = (Element)parent;
201             } else {
202                 break;
203             }
204         }
205         outputElement(startNode, topAtts);
206     }
207     
208   /**
209     * Walk an element of a document (traversing the children depth first)
210     * @param elem The DOM Element object to walk
211     * @exception SAXException On any error in the document
212     *
213     */

214     
215     private void walkNode (Node node) throws SAXException
216     {
217         if (node.hasChildNodes()) {
218             NodeList nit = node.getChildNodes();
219             for (int i=0; i<nit.getLength(); i++) {
220                 Node child = nit.item(i);
221                 switch (child.getNodeType()) {
222                     case Node.DOCUMENT_NODE:
223                         break; // should not happen
224
case Node.ELEMENT_NODE:
225                         Element element = (Element)child;
226                         nsSupport.pushContext();
227                         attlist.clear();
228                         nsDeclarations.clear();
229                         
230                         // we can't rely on namespace declaration attributes being present -
231
// there may be undeclared namespace prefixes. (If the DOM is a Saxon
232
// tree, there will be no namespace declaration attributes.) So we
233
// declare all namespaces encountered, to be on the safe side.
234

235                         String JavaDoc elname = element.getTagName();
236                         //if (elname.indexOf(':')>=0) {
237
// also need to do this for default namespace
238
try {
239                                 String JavaDoc prefix = element.getPrefix();
240                                 String JavaDoc uri = element.getNamespaceURI();
241                                 //System.err.println("Implicit Namespace: " + prefix + "=" + uri);
242
if (nsDeclarations.get(prefix)==null) {
243                                     nsSupport.declarePrefix(prefix, uri);
244                                     contentHandler.startPrefixMapping(prefix, uri);
245                                     nsDeclarations.put(prefix, uri);
246                                 }
247                             } catch (Throwable JavaDoc err) {
248                                 // it must be a level 1 DOM
249
}
250                         //}
251

252                         NamedNodeMap atts = element.getAttributes();
253                         for (int a1=0; a1<atts.getLength(); a1++) {
254                             Attr att = (Attr)atts.item(a1);
255                             String JavaDoc attname = att.getName();
256                             if (attname.equals("xmlns")) {
257                                 //System.err.println("Default namespace: " + att.getValue());
258
if (nsDeclarations.get("")==null) {
259                                     String JavaDoc uri = att.getValue();
260                                     nsSupport.declarePrefix("", uri);
261                                     contentHandler.startPrefixMapping("", uri);
262                                     nsDeclarations.put("", uri);
263                                 }
264                             } else if (attname.startsWith("xmlns:")) {
265                                 //System.err.println("Namespace: " + attname.substring(6) + "=" + att.getValue());
266
String JavaDoc prefix = attname.substring(6);
267                                 if (nsDeclarations.get(prefix)==null) {
268                                     String JavaDoc uri = att.getValue();
269                                     nsSupport.declarePrefix(prefix, uri);
270                                     contentHandler.startPrefixMapping(prefix, uri);
271                                     nsDeclarations.put(prefix, uri);
272                                 }
273                             } else if (attname.indexOf(':')>=0) {
274                                 try {
275                                     String JavaDoc prefix = att.getPrefix();
276                                     String JavaDoc uri = att.getNamespaceURI();
277                                     //System.err.println("Implicit Namespace: " + prefix + "=" + uri);
278
if (nsDeclarations.get(prefix)==null) {
279                                         nsSupport.declarePrefix(prefix, uri);
280                                         contentHandler.startPrefixMapping(prefix, uri);
281                                         nsDeclarations.put(prefix, uri);
282                                     }
283                                 } catch (Throwable JavaDoc err) {
284                                     // it must be a level 1 DOM
285
}
286                             }
287                         }
288                         for (int a2=0; a2<atts.getLength(); a2++) {
289                             Attr att = (Attr)atts.item(a2);
290                             String JavaDoc attname = att.getName();
291                             if (!attname.equals("xmlns") && !attname.startsWith("xmlns:")) {
292                                 //System.err.println("Processing attribute " + attname);
293
String JavaDoc[] parts2 = nsSupport.processName(attname, parts, true);
294                                 if (parts2==null) {
295                                     throw new SAXException("Undeclared namespace in " + attname);
296                                 }
297                                 attlist.addAttribute(
298                                     parts2[0], parts2[1], parts2[2], "CDATA", att.getValue());
299                             }
300                         }
301                         String JavaDoc[] elparts2 = nsSupport.processName(element.getTagName(), elparts, false);
302                         if (elparts2==null) {
303                             throw new SAXException("Undeclared namespace in " + element.getTagName());
304                         }
305                         String JavaDoc uri = elparts2[0];
306                         String JavaDoc local = elparts2[1];
307                         String JavaDoc raw = elparts2[2];
308
309                         contentHandler.startElement(uri, local, raw, attlist);
310                         
311                         walkNode(element);
312
313                         contentHandler.endElement(uri, local, raw);
314                         Enumeration JavaDoc prefixes = nsSupport.getDeclaredPrefixes();
315                         while (prefixes.hasMoreElements()) {
316                             String JavaDoc prefix = (String JavaDoc)prefixes.nextElement();
317                             contentHandler.endPrefixMapping(prefix);
318                         }
319                         nsSupport.popContext();
320                         break;
321
322                     case Node.ATTRIBUTE_NODE: // have already dealt with attributes
323
break;
324                     case Node.PROCESSING_INSTRUCTION_NODE:
325                         contentHandler.processingInstruction(
326                             ((ProcessingInstruction)child).getTarget(),
327                             ((ProcessingInstruction)child).getData());
328                         break;
329                     case Node.COMMENT_NODE:
330                         if (lexicalHandler!=null) {
331                             String JavaDoc text = ((Comment)child).getData();
332                             if (text!=null) {
333                                 lexicalHandler.comment(text.toCharArray(), 0, text.length());
334                             }
335                         }
336                         break;
337                     case Node.TEXT_NODE:
338                     case Node.CDATA_SECTION_NODE:
339                         String JavaDoc text = ((CharacterData)child).getData();
340                         if (text!=null) {
341                             contentHandler.characters(text.toCharArray(), 0, text.length());
342                         }
343                         break;
344                     case Node.ENTITY_REFERENCE_NODE:
345                         walkNode(child);
346                         break;
347                     default:
348                         break; // should not happen
349
}
350             }
351         }
352         
353     }
354
355     private void outputElement(Element element, NamedNodeMap atts) throws SAXException {
356         String JavaDoc[] elparts2 = nsSupport.processName(element.getTagName(), elparts, false);
357         if (elparts2==null) {
358             throw new SAXException("Undeclared namespace in " + element.getTagName());
359         }
360         String JavaDoc uri = elparts2[0];
361         String JavaDoc local = elparts2[1];
362         String JavaDoc raw = elparts2[2];
363       
364         for (int a2=0; a2<atts.getLength(); a2++) {
365             Attr att = (Attr)atts.item(a2);
366             String JavaDoc attname = att.getName();
367             if (!attname.equals("xmlns") && !attname.startsWith("xmlns:")) {
368                 //System.err.println("Processing attribute " + attname);
369
String JavaDoc[] parts2 = nsSupport.processName(attname, parts, true);
370                 if (parts2==null) {
371                     throw new SAXException("Undeclared namespace in " + attname);
372                 }
373                 attlist.addAttribute(
374                     parts2[0], parts2[1], parts2[2], "CDATA", att.getValue());
375             }
376         }
377
378         contentHandler.startElement(uri, local, raw, attlist);
379         
380         walkNode(element);
381
382         contentHandler.endElement(uri, local, raw);
383         Enumeration JavaDoc prefixes = nsSupport.getDeclaredPrefixes();
384         while (prefixes.hasMoreElements()) {
385             String JavaDoc prefix = (String JavaDoc)prefixes.nextElement();
386             contentHandler.endPrefixMapping(prefix);
387         }
388     }
389
390     private NamedNodeMap gatherNamespaces(Element element, boolean cumulative) {
391         if (!cumulative) {
392             nsSupport.pushContext();
393             attlist.clear();
394             nsDeclarations.clear();
395         }
396
397         // we can't rely on namespace declaration attributes being present -
398
// there may be undeclared namespace prefixes. (If the DOM is a Saxon
399
// tree, there will be no namespace declaration attributes.) So we
400
// declare all namespaces encountered, to be on the safe side.
401

402         try {
403             String JavaDoc prefix = element.getPrefix();
404             String JavaDoc uri = element.getNamespaceURI();
405             if (prefix==null) prefix="";
406             if (uri==null) uri="";
407             //System.err.println("Implicit Namespace: " + prefix + "=" + uri);
408
if (nsDeclarations.get(prefix)==null) {
409                 nsSupport.declarePrefix(prefix, uri);
410                 nsDeclarations.put(prefix, uri);
411             }
412         } catch (Throwable JavaDoc err) {
413             // it must be a level 1 DOM
414
}
415
416         NamedNodeMap atts = element.getAttributes();
417         for (int a1=0; a1<atts.getLength(); a1++) {
418             Attr att = (Attr)atts.item(a1);
419             String JavaDoc attname = att.getName();
420             if (attname.equals("xmlns")) {
421                 //System.err.println("Default namespace: " + att.getValue());
422
if (nsDeclarations.get("")==null) {
423                     String JavaDoc uri = att.getValue();
424                     nsSupport.declarePrefix("", uri);
425                     nsDeclarations.put("", uri);
426                 }
427             } else if (attname.startsWith("xmlns:")) {
428                 //System.err.println("Namespace: " + attname.substring(6) + "=" + att.getValue());
429
String JavaDoc prefix = attname.substring(6);
430                 if (nsDeclarations.get(prefix)==null) {
431                     String JavaDoc uri = att.getValue();
432                     nsSupport.declarePrefix(prefix, uri);
433                     nsDeclarations.put(prefix, uri);
434                 }
435             } else if (attname.indexOf(':')>=0) {
436                 try {
437                     String JavaDoc prefix = att.getPrefix();
438                     String JavaDoc uri = att.getNamespaceURI();
439                     //System.err.println("Implicit Namespace: " + prefix + "=" + uri);
440
if (nsDeclarations.get(prefix)==null) {
441                         nsSupport.declarePrefix(prefix, uri);
442                         //contentHandler.startPrefixMapping(prefix, uri);
443
nsDeclarations.put(prefix, uri);
444                     }
445                 } catch (Throwable JavaDoc err) {
446                     // it must be a level 1 DOM
447
}
448             }
449         }
450         return atts;
451     }
452     
453     //
454
// Implementation of org.xml.sax.Locator.
455
//
456

457     public void setSystemId(String JavaDoc systemId) {
458         this.systemId = systemId;
459     }
460
461     public String JavaDoc getPublicId ()
462     {
463         return null; // TODO
464
}
465
466     public String JavaDoc getSystemId ()
467     {
468         return systemId;
469     }
470
471     public int getLineNumber ()
472     {
473         return -1;
474     }
475
476     public int getColumnNumber ()
477     {
478         return -1;
479     }
480
481     // Features and properties
482

483     static final String JavaDoc FEATURE = "http://xml.org/sax/features/";
484     static final String JavaDoc HANDLER = "http://xml.org/sax/properties/";
485
486     /**
487      * <b>SAX2</b>: Tells the value of the specified feature flag.
488      *
489      * @exception SAXNotRecognizedException thrown if the feature flag
490      * is neither built in, nor yet assigned.
491      */

492      
493     public boolean getFeature (String JavaDoc featureId) throws SAXNotRecognizedException
494     {
495         if ((FEATURE + "validation").equals (featureId))
496             return false;
497
498         // external entities (both types) are currently always excluded
499
if ((FEATURE + "external-general-entities").equals (featureId)
500                 || (FEATURE + "external-parameter-entities").equals (featureId))
501         return false;
502
503         // element/attribute names are as namespace-sensitive
504
if ((FEATURE + "namespace-prefixes").equals (featureId))
505             return false;
506
507         // report element/attribute namespaces?
508
if ((FEATURE + "namespaces").equals (featureId))
509             return true;
510
511         // always interns: no
512
if ((FEATURE + "string-interning").equals (featureId))
513             return false;
514
515         throw new SAXNotRecognizedException (featureId);
516     }
517
518     /**
519      * <b>SAX2</b>: Returns the specified property.
520      *
521      * @exception SAXNotRecognizedException thrown if the property value
522      * is neither built in, nor yet stored.
523      */

524      
525     public Object JavaDoc getProperty (String JavaDoc name) throws SAXNotRecognizedException {
526         if (name.equals("http://xml.org/sax/properties/lexical-handler")) {
527             return lexicalHandler;
528         } else {
529             throw new SAXNotRecognizedException(name);
530         }
531     }
532
533     /**
534      * <b>SAX2</b>: Sets the state of feature flags in this parser. Some
535      * built-in feature flags are mutable; all flags not built-in are
536      * motable.
537      */

538     public void setFeature (String JavaDoc featureId, boolean on)
539     throws SAXNotRecognizedException, SAXNotSupportedException
540     {
541         if ((FEATURE + "validation").equals (featureId))
542             if (on) {
543                 throw new SAXNotSupportedException(featureId + " feature cannot be switched on");
544             } else {
545                 return;
546             }
547
548         // external entities (both types) are currently always excluded
549
if ((FEATURE + "external-general-entities").equals (featureId)
550                 || (FEATURE + "external-parameter-entities").equals (featureId) )
551             if (on) {
552                 throw new SAXNotSupportedException(featureId + " feature cannot be switched on");
553             } else {
554                 return;
555             }
556
557         // element/attribute names are as namespace-sensitive
558
if ((FEATURE + "namespace-prefixes").equals (featureId))
559             if (on) {
560                 throw new SAXNotSupportedException(featureId + " feature cannot be switched on");
561             } else {
562                 return;
563             }
564
565         // report element/attribute namespaces?
566
if ((FEATURE + "namespaces").equals (featureId))
567             if (!on) {
568                 throw new SAXNotSupportedException(featureId + " feature cannot be switched off");
569             } else {
570                 return;
571             }
572
573         // always interns: no
574
if ((FEATURE + "string-interning").equals (featureId))
575             if (on) {
576                 throw new SAXNotSupportedException(featureId + " feature cannot be switched on");
577             } else {
578                 return;
579             }
580
581         throw new SAXNotRecognizedException("Feature not recognized: " + featureId);
582     }
583
584     /**
585      * <b>SAX2</b>: Assigns the specified property. Like SAX1 handlers,
586      * these may be changed at any time.
587      */

588      
589     public void setProperty (String JavaDoc propertyId, Object JavaDoc property)
590     throws SAXNotRecognizedException, SAXNotSupportedException {
591         if (propertyId.equals("http://xml.org/sax/properties/lexical-handler")) {
592             if (property instanceof LexicalHandler JavaDoc) {
593                 lexicalHandler = (LexicalHandler JavaDoc)property;
594             } else {
595                 throw new SAXNotSupportedException(
596                     "Lexical Handler must be instance of org.xml.sax.ext.LexicalHandler");
597             }
598         } else {
599             throw new SAXNotRecognizedException(propertyId);
600         }
601     }
602
603 }
604 //
605
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
606
// you may not use this file except in compliance with the License. You may obtain a copy of the
607
// License at http://www.mozilla.org/MPL/
608
//
609
// Software distributed under the License is distributed on an "AS IS" basis,
610
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
611
// See the License for the specific language governing rights and limitations under the License.
612
//
613
// The Original Code is: all this file.
614
//
615
// The Initial Developer of the Original Code is
616
// Michael Kay of International Computers Limited (mhkay@iclway.co.uk).
617
//
618
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
619
//
620
// Contributor(s): none.
621
//
622
Popular Tags