1:
37:
38: package ;
39:
40: import ;
41: import ;
42:
43: import ;
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49:
50: import ;
51:
52:
53:
114: final public class DomParser implements XMLReader
115: {
116:
117: private DefaultHandler2 defaultHandler = new DefaultHandler2 ();
118:
119:
120: private ContentHandler contentHandler = defaultHandler;
121: private DTDHandler dtdHandler = defaultHandler;
122: private DeclHandler declHandler = defaultHandler;
123: private LexicalHandler lexicalHandler = defaultHandler;
124:
125:
126: private ErrorHandler errHandler = defaultHandler;
127: private EntityResolver resolver = defaultHandler;
128: private Locale locale = Locale.getDefault ();
129:
130:
131: private Node start;
132: private Node current;
133: private boolean isL2;
134: private boolean showNamespaces = true;
135: private boolean showXML1_0 = false;
136: private NamespaceSupport prefixStack = new NamespaceSupport ();
137: private boolean isDocument;
138:
139:
140:
143: public DomParser () {
144: }
145:
146:
151: public DomParser (Node node) {
152: setStart (node);
153: }
154:
155:
156:
157:
158:
159:
163: public EntityResolver getEntityResolver ()
164: {
165: return resolver;
166: }
167:
168:
172: public void setEntityResolver (EntityResolver resolver)
173: {
174: if (resolver == null)
175: resolver = defaultHandler;
176: this.resolver = resolver;
177: }
178:
179:
186: public void setLocale (Locale locale)
187: throws SAXException
188: {
189: if (locale == null)
190: locale = Locale.getDefault ();
191: this.locale = locale;
192: }
193:
194:
195:
196:
197:
198:
202: public ErrorHandler getErrorHandler ()
203: {
204: return errHandler;
205: }
206:
207:
211: public void setErrorHandler (ErrorHandler handler)
212: {
213: if (handler == null)
214: handler = defaultHandler;
215: errHandler = handler;
216: }
217:
218:
219:
220:
221:
225: public ContentHandler getContentHandler ()
226: {
227: return contentHandler;
228: }
229:
230:
234: public void setContentHandler (ContentHandler handler)
235: {
236: if (handler == null)
237: handler = defaultHandler;
238: contentHandler = handler;
239: }
240:
241:
245: public DTDHandler getDTDHandler ()
246: {
247: return dtdHandler;
248: }
249:
250:
254: public void setDTDHandler (DTDHandler handler)
255: {
256: if (handler == null)
257: handler = defaultHandler;
258: dtdHandler = handler;
259: }
260:
261:
262:
271: public void parse (String uri) throws SAXException
272: {
273: parse ();
274: }
275:
276:
285: public void parse (InputSource input) throws SAXException
286: {
287: parse ();
288: }
289:
290: private void parse () throws SAXException
291: {
292: try {
293: walk ();
294: } finally {
295: if (isDocument)
296: contentHandler.endDocument ();
297: current = null;
298: prefixStack.reset ();
299: }
300: }
301:
302: private boolean getIsL2 (Node node)
303: {
304: DOMImplementation impl;
305: Document doc;
306:
307: if (node instanceof Document)
308: doc = (Document) node;
309: else
310: doc = node.getOwnerDocument ();
311: if (doc == null)
312: throw new RuntimeException ("? unowned node - L2 DTD ?");
313: impl = doc.getImplementation ();
314: return impl.hasFeature ("XML", "2.0");
315: }
316:
317:
318: private static final String FEATURES = "http://xml.org/sax/features/";
319: private static final String HANDLERS = "http://xml.org/sax/properties/";
320:
321:
324: public boolean getFeature (String name)
325: throws SAXNotRecognizedException, SAXNotSupportedException
326: {
327:
328:
329:
330:
331:
332: if ((FEATURES + "validation").equals (name)
333: || (FEATURES + "external-general-entities")
334: .equals (name)
335: || (FEATURES + "external-parameter-entities")
336: .equals (name)
337: || (FEATURES + "string-interning").equals (name)
338: )
339: return false;
340:
341: if ((FEATURES + "namespaces").equals (name))
342: return showNamespaces;
343: if ((FEATURES + "namespace-prefixes").equals (name))
344: return showXML1_0;
345:
346: throw new SAXNotRecognizedException (name);
347: }
348:
349:
354: public Object getProperty (String name)
355: throws SAXNotRecognizedException, SAXNotSupportedException
356: {
357: if ((HANDLERS + "declaration-handler").equals (name))
358: return declHandler == defaultHandler ? null : declHandler;
359: if ((HANDLERS + "lexical-handler").equals (name))
360: return lexicalHandler == defaultHandler ? null : lexicalHandler;
361:
362: if ((HANDLERS + "dom-node").equals (name))
363: return current;
364:
365:
366: throw new SAXNotRecognizedException (name);
367: }
368:
369:
373: public void setFeature (String name, boolean state)
374: throws SAXNotRecognizedException, SAXNotSupportedException
375: {
376: if (current != null)
377: throw new IllegalStateException ("feature change midparse");
378:
379: boolean value = getFeature (name);
380:
381: if (value == state)
382: return;
383:
384: if ((FEATURES + "namespaces").equals (name)) {
385: if (!showXML1_0 && state == false)
386: throw new SAXNotSupportedException ("Illegal namespace "
387: + "processing configuration");
388: showNamespaces = state;
389: return;
390: }
391: if ((FEATURES + "namespace-prefixes").equals (name)) {
392: if (!showNamespaces && state == false)
393: throw new SAXNotSupportedException ("Illegal namespace "
394: + "processing configuration");
395: showXML1_0 = state;
396: return;
397: }
398:
399: throw new SAXNotSupportedException (name);
400: }
401:
402:
410: public void setProperty (String name, Object state)
411: throws SAXNotRecognizedException, SAXNotSupportedException
412: {
413: if ((HANDLERS + "declaration-handler").equals (name)) {
414: if (!(state instanceof DeclHandler || state == null))
415: throw new SAXNotSupportedException (name);
416: declHandler = (DeclHandler) state;
417: return;
418: }
419:
420: if ((HANDLERS + "lexical-handler").equals (name)) {
421: if (!(state instanceof LexicalHandler || state == null))
422: throw new SAXNotSupportedException (name);
423: lexicalHandler = (LexicalHandler) state;
424: return;
425: }
426:
427: if ((HANDLERS + "dom-node").equals (name)) {
428: if (state == null || state instanceof Node) {
429: if (current != null)
430: throw new SAXNotSupportedException (
431: "property is readonly during parse: " + name);
432: setStart ((Node) state);
433: return;
434: }
435: throw new SAXNotSupportedException ("not a DOM Node");
436: }
437:
438:
439: throw new SAXNotRecognizedException (name);
440: }
441:
442: private void setStart (Node property)
443: {
444: start = property;
445: if (start != null) {
446: isL2 = getIsL2 (start);
447: isDocument = (start instanceof Document);
448: }
449: }
450:
451:
452:
453:
454: private void walk ()
455: throws SAXException
456: {
457: int type;
458: NamedNodeMap nodes;
459: int length;
460: AttributesImpl attrs = new AttributesImpl ();
461: char chars [];
462: String ns, local;
463:
464: synchronized (this) {
465: if (current != null)
466: throw new IllegalStateException ("already walking tree");
467:
468:
469:
470: current = start;
471: }
472:
473: for (;;) {
474: type = current.getNodeType ();
475:
476:
477:
478:
479: switch (type) {
480:
481: case Node.DOCUMENT_NODE:
482: contentHandler.startDocument ();
483: break;
484:
485: case Node.ELEMENT_NODE:
486: nodes = current.getAttributes ();
487: length = nodes.getLength ();
488: prefixStack.pushContext ();
489: for (int i = 0; i < length; i++) {
490: Attr attr = (Attr) nodes.item (i);
491: String name = attr.getNodeName ();
492:
493: if (showNamespaces && name.startsWith ("xmlns")) {
494: String prefix;
495: String uri;
496:
497:
498:
499:
500: if ("xmlns".equals (name))
501: prefix = "";
502: else
503: prefix = name.substring (6);
504: uri = attr.getNodeValue ();
505:
506: prefixStack.declarePrefix (prefix, uri);
507: contentHandler.startPrefixMapping (prefix, uri);
508:
509: if (!showXML1_0)
510: continue;
511: }
512:
513:
514:
515:
516:
517:
518:
519:
520:
521:
522: if (showNamespaces) {
523: if (isL2) {
524: if ((ns = attr.getNamespaceURI ()) == null)
525: ns = "";
526:
527:
528: if ((local = attr.getLocalName ()) == null)
529: local = name;
530: } else {
531:
532: throw new RuntimeException (
533: "NYI, ns lookup when parsing L1 DOM");
534: }
535: } else
536: ns = local = "";
537: attrs.addAttribute (ns, local, name,
538: "CDATA", attr.getNodeValue ());
539: }
540: if (showNamespaces) {
541: if (isL2) {
542: if ((ns = current.getNamespaceURI ()) == null)
543: ns = "";
544:
545: if ((local = current.getLocalName ()) == null)
546: local = current.getNodeName ();
547: } else {
548:
549: throw new RuntimeException (
550: "NYI, ns lookup when parsing L1 DOM");
551: }
552: } else
553: ns = local = "";
554: contentHandler.startElement (ns, local,
555: current.getNodeName (), attrs);
556: if (length != 0)
557: attrs.clear ();
558: break;
559:
560: case Node.CDATA_SECTION_NODE:
561: lexicalHandler.startCDATA ();
562: chars = current.getNodeValue ().toCharArray ();
563: contentHandler.characters (chars, 0, chars.length);
564: lexicalHandler.endCDATA ();
565: break;
566:
567: case Node.COMMENT_NODE:
568: chars = current.getNodeValue ().toCharArray ();
569: lexicalHandler.comment (chars, 0, chars.length);
570: break;
571:
572: case Node.DOCUMENT_TYPE_NODE:
573: {
574: DocumentType doctype = (DocumentType) current;
575:
576:
577:
578:
579: if (isL2) {
580: lexicalHandler.startDTD (doctype.getName (),
581: doctype.getPublicId (),
582: doctype.getSystemId ());
583: } else
584: lexicalHandler.startDTD (doctype.getName (),
585: null, null);
586:
587:
588:
589:
590:
591:
592:
593:
594:
595:
596:
597:
598:
599:
600:
601: {
602: String message;
603: char buf [];
604:
605:
606:
607:
608:
609:
610: if (isL2 && doctype.getInternalSubset () != null)
611: message =
612: " Full DTD known; can't be shown using SAX2. ";
613:
614:
615:
616:
617:
618:
619: else
620: message =
621: " This DTD was was recreated using incomplete DOM L2 records. ";
622:
623: buf = message.toCharArray ();
624: lexicalHandler.comment (buf, 0, buf.length);
625: }
626:
627:
628: nodes = doctype.getNotations ();
629: length = nodes.getLength ();
630: for (int i = 0; i < length; i++) {
631: Notation notation = (Notation) nodes.item (i);
632: dtdHandler.notationDecl (
633: notation.getNodeName (),
634: notation.getPublicId (),
635: notation.getSystemId ());
636: }
637:
638:
639: nodes = doctype.getEntities ();
640: length = nodes.getLength ();
641: for (int i = 0; i < length; i++) {
642: Entity entity = (Entity) nodes.item (i);
643: String notation = entity.getNotationName ();
644:
645: if (notation != null)
646: dtdHandler.unparsedEntityDecl (
647: entity.getNodeName (),
648: entity.getPublicId (),
649: entity.getSystemId (),
650: notation);
651: else if (entity.getSystemId () != null)
652: declHandler.externalEntityDecl (
653: entity.getNodeName (),
654: entity.getPublicId (),
655: entity.getSystemId ());
656:
657:
658:
659:
660:
661:
662:
663:
664:
665: }
666:
667:
668:
669:
670:
671:
672: lexicalHandler.endDTD ();
673: }
674: break;
675:
676: case Node.ENTITY_REFERENCE_NODE:
677:
678:
679: lexicalHandler.startEntity (current.getNodeName ());
680: break;
681:
682: case Node.PROCESSING_INSTRUCTION_NODE:
683: contentHandler.processingInstruction (
684: current.getNodeName (), current.getNodeValue ());
685: break;
686:
687: case Node.TEXT_NODE:
688: chars = current.getNodeValue ().toCharArray ();
689: contentHandler.characters (chars, 0, chars.length);
690: break;
691:
692: default:
693:
694: throw new SAXException ("Illegal DOM Node type in Document: "
695: + current.getNodeType ());
696: }
697:
698:
699:
700:
701:
702:
703: Node next;
704:
705: switch (type) {
706: case Node.DOCUMENT_NODE:
707: case Node.ELEMENT_NODE:
708: case Node.ENTITY_REFERENCE_NODE:
709:
710:
711:
712:
713:
714: next = current.getFirstChild ();
715: if (next != null) {
716: current = next;
717: break;
718: }
719:
720:
721:
722:
723: callEnd (current);
724:
725:
726:
727: case Node.CDATA_SECTION_NODE:
728: case Node.COMMENT_NODE:
729: case Node.DOCUMENT_TYPE_NODE:
730: case Node.ENTITY_NODE:
731: case Node.PROCESSING_INSTRUCTION_NODE:
732: case Node.TEXT_NODE:
733:
734:
735:
736:
737:
738:
739: for (;;) {
740: if ((next = current.getNextSibling ()) != null)
741: break;
742: current = current.getParentNode ();
743: if (current == null || current == start)
744: return;
745: callEnd (current);
746: }
747: current = next;
748: break;
749:
750: default:
751: throw new SAXException (
752: "Illegal DOM Node type found: " + current.getNodeType ());
753: }
754: }
755: }
756:
757: private void callEnd (Node node) throws SAXException
758: {
759: switch (node.getNodeType ()) {
760:
761:
762: case Node.DOCUMENT_NODE:
763:
764:
765: return;
766:
767: case Node.ELEMENT_NODE:
768: if (showNamespaces) {
769: if (isL2)
770: contentHandler.endElement (
771: node.getNamespaceURI (),
772: node.getLocalName (),
773: node.getNodeName ());
774: else
775:
776: throw new RuntimeException (
777: "NYI, ns lookup when parsing L1 DOM");
778: for (Enumeration e = prefixStack.getDeclaredPrefixes ();
779: e.hasMoreElements ();
780: ) {
781: contentHandler.endPrefixMapping ((String) e.nextElement ());
782: }
783: } else
784: contentHandler.endElement ("", "", node.getNodeName ());
785: prefixStack.popContext ();
786: return;
787:
788: case Node.ENTITY_REFERENCE_NODE:
789:
790: lexicalHandler.endEntity (node.getNodeName ());
791: return;
792:
793:
794: case Node.DOCUMENT_FRAGMENT_NODE:
795: case Node.ATTRIBUTE_NODE:
796: return;
797:
798: default:
799: throw new SAXException (
800: "Illegal DOM container type found: "
801: + current.getNodeType ());
802: }
803: }
804: }