1 7 8 package org.dom4j.io; 9 10 import java.io.IOException ; 11 import java.util.HashMap ; 12 import java.util.Iterator ; 13 import java.util.List ; 14 import java.util.Map ; 15 16 import org.dom4j.Attribute; 17 import org.dom4j.Branch; 18 import org.dom4j.CDATA; 19 import org.dom4j.CharacterData; 20 import org.dom4j.Comment; 21 import org.dom4j.Document; 22 import org.dom4j.DocumentType; 23 import org.dom4j.Element; 24 import org.dom4j.Entity; 25 import org.dom4j.Namespace; 26 import org.dom4j.Node; 27 import org.dom4j.ProcessingInstruction; 28 import org.dom4j.Text; 29 import org.dom4j.tree.NamespaceStack; 30 31 import org.xml.sax.Attributes ; 32 import org.xml.sax.ContentHandler ; 33 import org.xml.sax.DTDHandler ; 34 import org.xml.sax.EntityResolver ; 35 import org.xml.sax.ErrorHandler ; 36 import org.xml.sax.InputSource ; 37 import org.xml.sax.SAXException ; 38 import org.xml.sax.SAXNotRecognizedException ; 39 import org.xml.sax.SAXNotSupportedException ; 40 import org.xml.sax.XMLReader ; 41 import org.xml.sax.ext.LexicalHandler ; 42 import org.xml.sax.helpers.AttributesImpl ; 43 import org.xml.sax.helpers.LocatorImpl ; 44 45 53 public class SAXWriter implements XMLReader { 54 protected static final String [] LEXICAL_HANDLER_NAMES = { 55 "http://xml.org/sax/properties/lexical-handler", 56 "http://xml.org/sax/handlers/LexicalHandler" }; 57 58 protected static final String FEATURE_NAMESPACE_PREFIXES 59 = "http://xml.org/sax/features/namespace-prefixes"; 60 61 protected static final String FEATURE_NAMESPACES 62 = "http://xml.org/sax/features/namespaces"; 63 64 65 private ContentHandler contentHandler; 66 67 68 private DTDHandler dtdHandler; 69 70 71 private EntityResolver entityResolver; 72 73 private ErrorHandler errorHandler; 74 75 76 private LexicalHandler lexicalHandler; 77 78 79 private AttributesImpl attributes = new AttributesImpl (); 80 81 82 private Map features = new HashMap (); 83 84 85 private Map properties = new HashMap (); 86 87 88 private boolean declareNamespaceAttributes; 89 90 public SAXWriter() { 91 properties.put(FEATURE_NAMESPACE_PREFIXES, Boolean.FALSE); 92 properties.put(FEATURE_NAMESPACE_PREFIXES, Boolean.TRUE); 93 } 94 95 public SAXWriter(ContentHandler contentHandler) { 96 this(); 97 this.contentHandler = contentHandler; 98 } 99 100 public SAXWriter(ContentHandler contentHandler, 101 LexicalHandler lexicalHandler) { 102 this(); 103 this.contentHandler = contentHandler; 104 this.lexicalHandler = lexicalHandler; 105 } 106 107 public SAXWriter(ContentHandler contentHandler, 108 LexicalHandler lexicalHandler, EntityResolver entityResolver) { 109 this(); 110 this.contentHandler = contentHandler; 111 this.lexicalHandler = lexicalHandler; 112 this.entityResolver = entityResolver; 113 } 114 115 124 public void write(Node node) throws SAXException { 125 int nodeType = node.getNodeType(); 126 127 switch (nodeType) { 128 case Node.ELEMENT_NODE: 129 write((Element) node); 130 131 break; 132 133 case Node.ATTRIBUTE_NODE: 134 write((Attribute) node); 135 136 break; 137 138 case Node.TEXT_NODE: 139 write(node.getText()); 140 141 break; 142 143 case Node.CDATA_SECTION_NODE: 144 write((CDATA) node); 145 146 break; 147 148 case Node.ENTITY_REFERENCE_NODE: 149 write((Entity) node); 150 151 break; 152 153 case Node.PROCESSING_INSTRUCTION_NODE: 154 write((ProcessingInstruction) node); 155 156 break; 157 158 case Node.COMMENT_NODE: 159 write((Comment) node); 160 161 break; 162 163 case Node.DOCUMENT_NODE: 164 write((Document) node); 165 166 break; 167 168 case Node.DOCUMENT_TYPE_NODE: 169 write((DocumentType) node); 170 171 break; 172 173 case Node.NAMESPACE_NODE: 174 175 break; 178 179 default: 180 throw new SAXException ("Invalid node type: " + node); 181 } 182 } 183 184 193 public void write(Document document) throws SAXException { 194 if (document != null) { 195 checkForNullHandlers(); 196 197 documentLocator(document); 198 startDocument(); 199 entityResolver(document); 200 dtdHandler(document); 201 202 writeContent(document, new NamespaceStack()); 203 endDocument(); 204 } 205 } 206 207 216 public void write(Element element) throws SAXException { 217 write(element, new NamespaceStack()); 218 } 219 220 232 public void writeOpen(Element element) throws SAXException { 233 startElement(element, null); 234 } 235 236 247 public void writeClose(Element element) throws SAXException { 248 endElement(element); 249 } 250 251 260 public void write(String text) throws SAXException { 261 if (text != null) { 262 char[] chars = text.toCharArray(); 263 contentHandler.characters(chars, 0, chars.length); 264 } 265 } 266 267 276 public void write(CDATA cdata) throws SAXException { 277 String text = cdata.getText(); 278 279 if (lexicalHandler != null) { 280 lexicalHandler.startCDATA(); 281 write(text); 282 lexicalHandler.endCDATA(); 283 } else { 284 write(text); 285 } 286 } 287 288 297 public void write(Comment comment) throws SAXException { 298 if (lexicalHandler != null) { 299 String text = comment.getText(); 300 char[] chars = text.toCharArray(); 301 lexicalHandler.comment(chars, 0, chars.length); 302 } 303 } 304 305 314 public void write(Entity entity) throws SAXException { 315 String text = entity.getText(); 316 317 if (lexicalHandler != null) { 318 String name = entity.getName(); 319 lexicalHandler.startEntity(name); 320 write(text); 321 lexicalHandler.endEntity(name); 322 } else { 323 write(text); 324 } 325 } 326 327 336 public void write(ProcessingInstruction pi) throws SAXException { 337 String target = pi.getTarget(); 338 String text = pi.getText(); 339 contentHandler.processingInstruction(target, text); 340 } 341 342 350 public boolean isDeclareNamespaceAttributes() { 351 return declareNamespaceAttributes; 352 } 353 354 362 public void setDeclareNamespaceAttributes(boolean declareNamespaceAttrs) { 363 this.declareNamespaceAttributes = declareNamespaceAttrs; 364 } 365 366 369 375 public ContentHandler getContentHandler() { 376 return contentHandler; 377 } 378 379 386 public void setContentHandler(ContentHandler contentHandler) { 387 this.contentHandler = contentHandler; 388 } 389 390 395 public DTDHandler getDTDHandler() { 396 return dtdHandler; 397 } 398 399 405 public void setDTDHandler(DTDHandler handler) { 406 this.dtdHandler = handler; 407 } 408 409 414 public ErrorHandler getErrorHandler() { 415 return errorHandler; 416 } 417 418 424 public void setErrorHandler(ErrorHandler errorHandler) { 425 this.errorHandler = errorHandler; 426 } 427 428 434 public EntityResolver getEntityResolver() { 435 return entityResolver; 436 } 437 438 444 public void setEntityResolver(EntityResolver entityResolver) { 445 this.entityResolver = entityResolver; 446 } 447 448 454 public LexicalHandler getLexicalHandler() { 455 return lexicalHandler; 456 } 457 458 464 public void setLexicalHandler(LexicalHandler lexicalHandler) { 465 this.lexicalHandler = lexicalHandler; 466 } 467 468 474 public void setXMLReader(XMLReader xmlReader) { 475 setContentHandler(xmlReader.getContentHandler()); 476 setDTDHandler(xmlReader.getDTDHandler()); 477 setEntityResolver(xmlReader.getEntityResolver()); 478 setErrorHandler(xmlReader.getErrorHandler()); 479 } 480 481 494 public boolean getFeature(String name) throws SAXNotRecognizedException , 495 SAXNotSupportedException { 496 Boolean answer = (Boolean ) features.get(name); 497 498 return (answer != null) && answer.booleanValue(); 499 } 500 501 515 public void setFeature(String name, boolean value) 516 throws SAXNotRecognizedException , SAXNotSupportedException { 517 if (FEATURE_NAMESPACE_PREFIXES.equals(name)) { 518 setDeclareNamespaceAttributes(value); 519 } else if (FEATURE_NAMESPACE_PREFIXES.equals(name)) { 520 if (!value) { 521 String msg = "Namespace feature is always supported in dom4j"; 522 throw new SAXNotSupportedException (msg); 523 } 524 } 525 526 features.put(name, (value) ? Boolean.TRUE : Boolean.FALSE); 527 } 528 529 537 public void setProperty(String name, Object value) { 538 for (int i = 0; i < LEXICAL_HANDLER_NAMES.length; i++) { 539 if (LEXICAL_HANDLER_NAMES[i].equals(name)) { 540 setLexicalHandler((LexicalHandler ) value); 541 542 return; 543 } 544 } 545 546 properties.put(name, value); 547 } 548 549 562 public Object getProperty(String name) throws SAXNotRecognizedException , 563 SAXNotSupportedException { 564 for (int i = 0; i < LEXICAL_HANDLER_NAMES.length; i++) { 565 if (LEXICAL_HANDLER_NAMES[i].equals(name)) { 566 return getLexicalHandler(); 567 } 568 } 569 570 return properties.get(name); 571 } 572 573 582 public void parse(String systemId) throws SAXNotSupportedException { 583 throw new SAXNotSupportedException ("This XMLReader can only accept" 584 + " <dom4j> InputSource objects"); 585 } 586 587 599 public void parse(InputSource input) throws SAXException { 600 if (input instanceof DocumentInputSource) { 601 DocumentInputSource documentInput = (DocumentInputSource) input; 602 Document document = documentInput.getDocument(); 603 write(document); 604 } else { 605 throw new SAXNotSupportedException ( 606 "This XMLReader can only accept " 607 + "<dom4j> InputSource objects"); 608 } 609 } 610 611 protected void writeContent(Branch branch, NamespaceStack namespaceStack) 614 throws SAXException { 615 for (Iterator iter = branch.nodeIterator(); iter.hasNext();) { 616 Object object = iter.next(); 617 618 if (object instanceof Element) { 619 write((Element) object, namespaceStack); 620 } else if (object instanceof CharacterData) { 621 if (object instanceof Text) { 622 Text text = (Text) object; 623 write(text.getText()); 624 } else if (object instanceof CDATA) { 625 write((CDATA) object); 626 } else if (object instanceof Comment) { 627 write((Comment) object); 628 } else { 629 throw new SAXException ("Invalid Node in DOM4J content: " 630 + object + " of type: " + object.getClass()); 631 } 632 } else if (object instanceof String ) { 633 write((String ) object); 634 } else if (object instanceof Entity) { 635 write((Entity) object); 636 } else if (object instanceof ProcessingInstruction) { 637 write((ProcessingInstruction) object); 638 } else if (object instanceof Namespace) { 639 write((Namespace) object); 640 } else { 641 throw new SAXException ("Invalid Node in DOM4J content: " 642 + object); 643 } 644 } 645 } 646 647 660 protected void documentLocator(Document document) throws SAXException { 661 LocatorImpl locator = new LocatorImpl (); 662 663 String publicID = null; 664 String systemID = null; 665 DocumentType docType = document.getDocType(); 666 667 if (docType != null) { 668 publicID = docType.getPublicID(); 669 systemID = docType.getSystemID(); 670 } 671 672 if (publicID != null) { 673 locator.setPublicId(publicID); 674 } 675 676 if (systemID != null) { 677 locator.setSystemId(systemID); 678 } 679 680 locator.setLineNumber(-1); 681 locator.setColumnNumber(-1); 682 683 contentHandler.setDocumentLocator(locator); 684 } 685 686 protected void entityResolver(Document document) throws SAXException { 687 if (entityResolver != null) { 688 DocumentType docType = document.getDocType(); 689 690 if (docType != null) { 691 String publicID = docType.getPublicID(); 692 String systemID = docType.getSystemID(); 693 694 if ((publicID != null) || (systemID != null)) { 695 try { 696 entityResolver.resolveEntity(publicID, systemID); 697 } catch (IOException e) { 698 throw new SAXException ("Could not resolve publicID: " 699 + publicID + " systemID: " + systemID, e); 700 } 701 } 702 } 703 } 704 } 705 706 716 protected void dtdHandler(Document document) throws SAXException { 717 } 718 719 protected void startDocument() throws SAXException { 720 contentHandler.startDocument(); 721 } 722 723 protected void endDocument() throws SAXException { 724 contentHandler.endDocument(); 725 } 726 727 protected void write(Element element, NamespaceStack namespaceStack) 728 throws SAXException { 729 int stackSize = namespaceStack.size(); 730 AttributesImpl namespaceAttributes = startPrefixMapping(element, 731 namespaceStack); 732 startElement(element, namespaceAttributes); 733 writeContent(element, namespaceStack); 734 endElement(element); 735 endPrefixMapping(namespaceStack, stackSize); 736 } 737 738 752 protected AttributesImpl startPrefixMapping(Element element, 753 NamespaceStack namespaceStack) throws SAXException { 754 AttributesImpl namespaceAttributes = null; 755 756 Namespace elementNamespace = element.getNamespace(); 758 759 if ((elementNamespace != null) 760 && !isIgnoreableNamespace(elementNamespace, namespaceStack)) { 761 namespaceStack.push(elementNamespace); 762 contentHandler.startPrefixMapping(elementNamespace.getPrefix(), 763 elementNamespace.getURI()); 764 namespaceAttributes = addNamespaceAttribute(namespaceAttributes, 765 elementNamespace); 766 } 767 768 List declaredNamespaces = element.declaredNamespaces(); 769 770 for (int i = 0, size = declaredNamespaces.size(); i < size; i++) { 771 Namespace namespace = (Namespace) declaredNamespaces.get(i); 772 773 if (!isIgnoreableNamespace(namespace, namespaceStack)) { 774 namespaceStack.push(namespace); 775 contentHandler.startPrefixMapping(namespace.getPrefix(), 776 namespace.getURI()); 777 namespaceAttributes = addNamespaceAttribute( 778 namespaceAttributes, namespace); 779 } 780 } 781 782 return namespaceAttributes; 783 } 784 785 797 protected void endPrefixMapping(NamespaceStack stack, int stackSize) 798 throws SAXException { 799 while (stack.size() > stackSize) { 800 Namespace namespace = stack.pop(); 801 802 if (namespace != null) { 803 contentHandler.endPrefixMapping(namespace.getPrefix()); 804 } 805 } 806 } 807 808 protected void startElement(Element element, 809 AttributesImpl namespaceAttributes) throws SAXException { 810 contentHandler.startElement(element.getNamespaceURI(), element 811 .getName(), element.getQualifiedName(), createAttributes( 812 element, namespaceAttributes)); 813 } 814 815 protected void endElement(Element element) throws SAXException { 816 contentHandler.endElement(element.getNamespaceURI(), element.getName(), 817 element.getQualifiedName()); 818 } 819 820 protected Attributes createAttributes(Element element, 821 Attributes namespaceAttributes) throws SAXException { 822 attributes.clear(); 823 824 if (namespaceAttributes != null) { 825 attributes.setAttributes(namespaceAttributes); 826 } 827 828 for (Iterator iter = element.attributeIterator(); iter.hasNext();) { 829 Attribute attribute = (Attribute) iter.next(); 830 attributes.addAttribute(attribute.getNamespaceURI(), attribute 831 .getName(), attribute.getQualifiedName(), "CDATA", 832 attribute.getValue()); 833 } 834 835 return attributes; 836 } 837 838 850 protected AttributesImpl addNamespaceAttribute(AttributesImpl attrs, 851 Namespace namespace) { 852 if (declareNamespaceAttributes) { 853 if (attrs == null) { 854 attrs = new AttributesImpl (); 855 } 856 857 String prefix = namespace.getPrefix(); 858 String qualifiedName = "xmlns"; 859 860 if ((prefix != null) && (prefix.length() > 0)) { 861 qualifiedName = "xmlns:" + prefix; 862 } 863 864 String uri = ""; 865 String localName = prefix; 866 String type = "CDATA"; 867 String value = namespace.getURI(); 868 869 attrs.addAttribute(uri, localName, qualifiedName, type, value); 870 } 871 872 return attrs; 873 } 874 875 887 protected boolean isIgnoreableNamespace(Namespace namespace, 888 NamespaceStack namespaceStack) { 889 if (namespace.equals(Namespace.NO_NAMESPACE) 890 || namespace.equals(Namespace.XML_NAMESPACE)) { 891 return true; 892 } 893 894 String uri = namespace.getURI(); 895 896 if ((uri == null) || (uri.length() <= 0)) { 897 return true; 898 } 899 900 return namespaceStack.contains(namespace); 901 } 902 903 906 protected void checkForNullHandlers() { 907 } 908 } 909 910 946 | Popular Tags |