| 1 56 57 package org.jdom.output; 58 59 import java.io.*; 60 import java.lang.reflect.*; 61 import java.util.*; 62 63 import org.jdom.*; 64 import org.xml.sax.*; 65 import org.xml.sax.ext.*; 66 import org.xml.sax.helpers.*; 67 68 91 public class SAXOutputter { 92 93 private static final String CVS_ID = 94 "@(#) $RCSfile: SAXOutputter.java,v $ $Revision: 1.38 $ $Date: 2004/12/11 00:15:24 $ $Name: $"; 95 96 97 private static final String NAMESPACES_SAX_FEATURE = 98 "http://xml.org/sax/features/namespaces"; 99 100 101 private static final String NS_PREFIXES_SAX_FEATURE = 102 "http://xml.org/sax/features/namespace-prefixes"; 103 104 105 private static final String VALIDATION_SAX_FEATURE = 106 "http://xml.org/sax/features/validation"; 107 108 109 private static final String LEXICAL_HANDLER_SAX_PROPERTY = 110 "http://xml.org/sax/properties/lexical-handler"; 111 112 113 private static final String DECL_HANDLER_SAX_PROPERTY = 114 "http://xml.org/sax/properties/declaration-handler"; 115 116 121 private static final String LEXICAL_HANDLER_ALT_PROPERTY = 122 "http://xml.org/sax/handlers/LexicalHandler"; 123 124 125 private static final String DECL_HANDLER_ALT_PROPERTY = 126 "http://xml.org/sax/handlers/DeclHandler"; 127 128 132 private static final String [] attrTypeToNameMap = new String [] { 133 "CDATA", "CDATA", "ID", "IDREF", "IDREFS", "ENTITY", "ENTITIES", "NMTOKEN", "NMTOKENS", "NOTATION", "NMTOKEN", }; 145 146 147 private ContentHandler contentHandler; 148 149 150 private ErrorHandler errorHandler; 151 152 153 private DTDHandler dtdHandler; 154 155 156 private EntityResolver entityResolver; 157 158 159 private LexicalHandler lexicalHandler; 160 161 162 private DeclHandler declHandler; 163 164 171 private boolean declareNamespaces = false; 172 173 177 private boolean reportDtdEvents = true; 178 179 183 private JDOMLocator locator = null; 184 185 190 public SAXOutputter() { 191 } 192 193 200 public SAXOutputter(ContentHandler contentHandler) { 201 this(contentHandler, null, null, null, null); 202 } 203 204 216 public SAXOutputter(ContentHandler contentHandler, 217 ErrorHandler errorHandler, 218 DTDHandler dtdHandler, 219 EntityResolver entityResolver) { 220 this(contentHandler, errorHandler, dtdHandler, entityResolver, null); 221 } 222 223 236 public SAXOutputter(ContentHandler contentHandler, 237 ErrorHandler errorHandler, 238 DTDHandler dtdHandler, 239 EntityResolver entityResolver, 240 LexicalHandler lexicalHandler) { 241 this.contentHandler = contentHandler; 242 this.errorHandler = errorHandler; 243 this.dtdHandler = dtdHandler; 244 this.entityResolver = entityResolver; 245 this.lexicalHandler = lexicalHandler; 246 } 247 248 254 public void setContentHandler(ContentHandler contentHandler) { 255 this.contentHandler = contentHandler; 256 } 257 258 264 public ContentHandler getContentHandler() { 265 return this.contentHandler; 266 } 267 268 273 public void setErrorHandler(ErrorHandler errorHandler) { 274 this.errorHandler = errorHandler; 275 } 276 277 283 public ErrorHandler getErrorHandler() { 284 return this.errorHandler; 285 } 286 287 292 public void setDTDHandler(DTDHandler dtdHandler) { 293 this.dtdHandler = dtdHandler; 294 } 295 296 302 public DTDHandler getDTDHandler() { 303 return this.dtdHandler; 304 } 305 306 311 public void setEntityResolver(EntityResolver entityResolver) { 312 this.entityResolver = entityResolver; 313 } 314 315 321 public EntityResolver getEntityResolver() { 322 return this.entityResolver; 323 } 324 325 330 public void setLexicalHandler(LexicalHandler lexicalHandler) { 331 this.lexicalHandler = lexicalHandler; 332 } 333 334 340 public LexicalHandler getLexicalHandler() { 341 return this.lexicalHandler; 342 } 343 344 349 public void setDeclHandler(DeclHandler declHandler) { 350 this.declHandler = declHandler; 351 } 352 353 359 public DeclHandler getDeclHandler() { 360 return this.declHandler; 361 } 362 363 370 public boolean getReportNamespaceDeclarations() { 371 return declareNamespaces; 372 } 373 374 382 public void setReportNamespaceDeclarations(boolean declareNamespaces) { 383 this.declareNamespaces = declareNamespaces; 384 } 385 386 391 public boolean getReportDTDEvents() { 392 return reportDtdEvents; 393 } 394 395 402 public void setReportDTDEvents(boolean reportDtdEvents) { 403 this.reportDtdEvents = reportDtdEvents; 404 } 405 406 444 public void setFeature(String name, boolean value) 445 throws SAXNotRecognizedException, SAXNotSupportedException { 446 if (NS_PREFIXES_SAX_FEATURE.equals(name)) { 447 this.setReportNamespaceDeclarations(value); 449 } 450 else { 451 if (NAMESPACES_SAX_FEATURE.equals(name)) { 452 if (value != true) { 453 throw new SAXNotSupportedException(name); 455 } 456 } 458 else { 459 if (VALIDATION_SAX_FEATURE.equals(name)) { 460 this.setReportDTDEvents(value); 462 } 463 else { 464 throw new SAXNotRecognizedException(name); 466 } 467 } 468 } 469 } 470 471 484 public boolean getFeature(String name) 485 throws SAXNotRecognizedException, SAXNotSupportedException { 486 if (NS_PREFIXES_SAX_FEATURE.equals(name)) { 487 return (this.declareNamespaces); 489 } 490 else { 491 if (NAMESPACES_SAX_FEATURE.equals(name)) { 492 return (true); 494 } 495 else { 496 if (VALIDATION_SAX_FEATURE.equals(name)) { 497 return (this.reportDtdEvents); 499 } 500 else { 501 throw new SAXNotRecognizedException(name); 503 } 504 } 505 } 506 } 507 508 539 public void setProperty(String name, Object value) 540 throws SAXNotRecognizedException, SAXNotSupportedException { 541 if ((LEXICAL_HANDLER_SAX_PROPERTY.equals(name)) || 542 (LEXICAL_HANDLER_ALT_PROPERTY.equals(name))) { 543 this.setLexicalHandler((LexicalHandler)value); 544 } 545 else { 546 if ((DECL_HANDLER_SAX_PROPERTY.equals(name)) || 547 (DECL_HANDLER_ALT_PROPERTY.equals(name))) { 548 this.setDeclHandler((DeclHandler)value); 549 } 550 else { 551 throw new SAXNotRecognizedException(name); 552 } 553 } 554 } 555 556 568 public Object getProperty(String name) 569 throws SAXNotRecognizedException, SAXNotSupportedException { 570 if ((LEXICAL_HANDLER_SAX_PROPERTY.equals(name)) || 571 (LEXICAL_HANDLER_ALT_PROPERTY.equals(name))) { 572 return this.getLexicalHandler(); 573 } 574 else { 575 if ((DECL_HANDLER_SAX_PROPERTY.equals(name)) || 576 (DECL_HANDLER_ALT_PROPERTY.equals(name))) { 577 return this.getDeclHandler(); 578 } 579 else { 580 throw new SAXNotRecognizedException(name); 581 } 582 } 583 } 584 585 586 594 public void output(Document document) throws JDOMException { 595 if (document == null) { 596 return; 597 } 598 599 documentLocator(document); 601 602 startDocument(); 604 605 if (this.reportDtdEvents) { 607 dtdEvents(document); 608 } 609 610 Iterator i = document.getContent().iterator(); 613 while (i.hasNext()) { 614 Object obj = i.next(); 615 616 locator.setNode(obj); 618 619 if (obj instanceof Element) { 620 element(document.getRootElement(), new NamespaceStack()); 622 } 623 else if (obj instanceof ProcessingInstruction) { 624 processingInstruction((ProcessingInstruction) obj); 626 } 627 else if (obj instanceof Comment) { 628 comment(((Comment) obj).getText()); 630 } 631 } 632 633 endDocument(); 635 } 636 637 654 public void output(List nodes) throws JDOMException { 655 if ((nodes == null) || (nodes.size() == 0)) { 656 return; 657 } 658 659 documentLocator(null); 661 662 startDocument(); 664 665 elementContent(nodes, new NamespaceStack()); 667 668 endDocument(); 670 } 671 672 680 public void output(Element node) throws JDOMException { 681 if (node == null) { 682 return; 683 } 684 685 documentLocator(null); 687 688 startDocument(); 690 691 elementContent(node, new NamespaceStack()); 693 694 endDocument(); 696 } 697 698 716 public void outputFragment(List nodes) throws JDOMException { 717 if ((nodes == null) || (nodes.size() == 0)) { 718 return; 719 } 720 721 elementContent(nodes, new NamespaceStack()); 723 } 724 725 743 public void outputFragment(Content node) throws JDOMException { 744 if (node == null) { 745 return; 746 } 747 748 elementContent(node, new NamespaceStack()); 750 } 751 752 759 private void dtdEvents(Document document) throws JDOMException { 760 DocType docType = document.getDocType(); 761 762 if ((docType != null) && 764 ((dtdHandler != null) || (declHandler != null))) { 765 766 String dtdDoc = new XMLOutputter().outputString(docType); 768 769 try { 770 createDTDParser().parse(new InputSource( 772 new StringReader(dtdDoc))); 773 774 } 777 catch (SAXParseException e) { 778 } 780 catch (SAXException e) { 781 throw new JDOMException("DTD parsing error", e); 782 } 783 catch (IOException e) { 784 throw new JDOMException("DTD parsing error", e); 785 } 786 } 787 } 788 789 800 private void documentLocator(Document document) { 801 locator = new JDOMLocator(); 802 String publicID = null; 803 String systemID = null; 804 805 if (document != null) { 806 DocType docType = document.getDocType(); 807 if (docType != null) { 808 publicID = docType.getPublicID(); 809 systemID = docType.getSystemID(); 810 } 811 } 812 locator.setPublicId(publicID); 813 locator.setSystemId(systemID); 814 locator.setLineNumber(-1); 815 locator.setColumnNumber(-1); 816 817 contentHandler.setDocumentLocator(locator); 818 } 819 820 826 private void startDocument() throws JDOMException { 827 try { 828 contentHandler.startDocument(); 829 } 830 catch (SAXException se) { 831 throw new JDOMException("Exception in startDocument", se); 832 } 833 } 834 835 841 private void endDocument() throws JDOMException { 842 try { 843 contentHandler.endDocument(); 844 845 locator = null; 847 } 848 catch (SAXException se) { 849 throw new JDOMException("Exception in endDocument", se); 850 } 851 } 852 853 861 private void processingInstruction(ProcessingInstruction pi) 862 throws JDOMException { 863 if (pi != null) { 864 String target = pi.getTarget(); 865 String data = pi.getData(); 866 try { 867 contentHandler.processingInstruction(target, data); 868 } 869 catch (SAXException se) { 870 throw new JDOMException( 871 "Exception in processingInstruction", se); 872 } 873 } 874 } 875 876 885 private void element(Element element, NamespaceStack namespaces) 886 throws JDOMException { 887 int previouslyDeclaredNamespaces = namespaces.size(); 889 890 Attributes nsAtts = startPrefixMapping(element, namespaces); 892 893 startElement(element, nsAtts); 895 896 elementContent(element.getContent(), namespaces); 898 899 locator.setNode(element); 901 902 endElement(element); 904 905 endPrefixMapping(namespaces, previouslyDeclaredNamespaces); 907 } 908 909 922 private Attributes startPrefixMapping(Element element, 923 NamespaceStack namespaces) 924 throws JDOMException { 925 AttributesImpl nsAtts = null; 927 Namespace ns = element.getNamespace(); 928 if (ns != Namespace.XML_NAMESPACE) { 929 String prefix = ns.getPrefix(); 930 String uri = namespaces.getURI(prefix); 931 if (!ns.getURI().equals(uri)) { 932 namespaces.push(ns); 933 nsAtts = this.addNsAttribute(nsAtts, ns); 934 try { 935 contentHandler.startPrefixMapping(prefix, ns.getURI()); 936 } 937 catch (SAXException se) { 938 throw new JDOMException( 939 "Exception in startPrefixMapping", se); 940 } 941 } 942 } 943 944 List additionalNamespaces = element.getAdditionalNamespaces(); 946 if (additionalNamespaces != null) { 947 Iterator itr = additionalNamespaces.iterator(); 948 while (itr.hasNext()) { 949 ns = (Namespace)itr.next(); 950 String prefix = ns.getPrefix(); 951 String uri = namespaces.getURI(prefix); 952 if (!ns.getURI().equals(uri)) { 953 namespaces.push(ns); 954 nsAtts = this.addNsAttribute(nsAtts, ns); 955 try { 956 contentHandler.startPrefixMapping(prefix, ns.getURI()); 957 } 958 catch (SAXException se) { 959 throw new JDOMException( 960 "Exception in startPrefixMapping", se); 961 } 962 } 963 } 964 } 965 return nsAtts; 966 } 967 968 979 private void |