1 7 8 package org.dom4j.io; 9 10 import java.lang.reflect.Method ; 11 import java.util.ArrayList ; 12 import java.util.HashMap ; 13 import java.util.List ; 14 import java.util.Map ; 15 16 import org.dom4j.Branch; 17 import org.dom4j.Document; 18 import org.dom4j.DocumentFactory; 19 import org.dom4j.DocumentType; 20 import org.dom4j.Element; 21 import org.dom4j.ElementHandler; 22 import org.dom4j.Namespace; 23 import org.dom4j.QName; 24 import org.dom4j.dtd.AttributeDecl; 25 import org.dom4j.dtd.ElementDecl; 26 import org.dom4j.dtd.ExternalEntityDecl; 27 import org.dom4j.dtd.InternalEntityDecl; 28 import org.dom4j.tree.AbstractElement; 29 import org.dom4j.tree.NamespaceStack; 30 31 import org.xml.sax.Attributes ; 32 import org.xml.sax.DTDHandler ; 33 import org.xml.sax.EntityResolver ; 34 import org.xml.sax.InputSource ; 35 import org.xml.sax.Locator ; 36 import org.xml.sax.SAXException ; 37 import org.xml.sax.SAXParseException ; 38 import org.xml.sax.ext.DeclHandler ; 39 import org.xml.sax.ext.LexicalHandler ; 40 import org.xml.sax.helpers.DefaultHandler ; 41 42 50 public class SAXContentHandler extends DefaultHandler implements 51 LexicalHandler , DeclHandler , DTDHandler { 52 53 private DocumentFactory documentFactory; 54 55 56 private Document document; 57 58 59 private ElementStack elementStack; 60 61 62 private NamespaceStack namespaceStack; 63 64 65 private ElementHandler elementHandler; 66 67 68 private Locator locator; 69 70 71 private String entity; 72 73 74 private boolean insideDTDSection; 75 76 77 private boolean insideCDATASection; 78 79 83 private StringBuffer cdataText; 84 85 86 private Map availableNamespaceMap = new HashMap (); 87 88 89 private List declaredNamespaceList = new ArrayList (); 90 91 92 private List internalDTDDeclarations; 93 94 95 private List externalDTDDeclarations; 96 97 98 private int declaredNamespaceIndex; 99 100 101 private EntityResolver entityResolver; 102 103 private InputSource inputSource; 104 105 106 private Element currentElement; 107 108 109 private boolean includeInternalDTDDeclarations = false; 110 111 112 private boolean includeExternalDTDDeclarations = false; 113 114 115 private int entityLevel; 116 117 118 private boolean internalDTDsubset = false; 119 120 121 private boolean mergeAdjacentText = false; 122 123 124 private boolean textInTextBuffer = false; 125 126 127 private boolean ignoreComments = false; 128 129 130 private StringBuffer textBuffer; 131 132 133 private boolean stripWhitespaceText = false; 134 135 public SAXContentHandler() { 136 this(DocumentFactory.getInstance()); 137 } 138 139 public SAXContentHandler(DocumentFactory documentFactory) { 140 this(documentFactory, null); 141 } 142 143 public SAXContentHandler(DocumentFactory documentFactory, 144 ElementHandler elementHandler) { 145 this(documentFactory, elementHandler, null); 146 this.elementStack = createElementStack(); 147 } 148 149 public SAXContentHandler(DocumentFactory documentFactory, 150 ElementHandler elementHandler, ElementStack elementStack) { 151 this.documentFactory = documentFactory; 152 this.elementHandler = elementHandler; 153 this.elementStack = elementStack; 154 this.namespaceStack = new NamespaceStack(documentFactory); 155 } 156 157 162 public Document getDocument() { 163 if (document == null) { 164 document = createDocument(); 165 } 166 167 return document; 168 } 169 170 public void setDocumentLocator(Locator documentLocator) { 173 this.locator = documentLocator; 174 } 175 176 public void processingInstruction(String target, String data) 177 throws SAXException { 178 if (mergeAdjacentText && textInTextBuffer) { 179 completeCurrentTextNode(); 180 } 181 182 if (currentElement != null) { 183 currentElement.addProcessingInstruction(target, data); 184 } else { 185 getDocument().addProcessingInstruction(target, data); 186 } 187 } 188 189 public void startPrefixMapping(String prefix, String uri) 190 throws SAXException { 191 namespaceStack.push(prefix, uri); 192 } 193 194 public void endPrefixMapping(String prefix) throws SAXException { 195 namespaceStack.pop(prefix); 196 declaredNamespaceIndex = namespaceStack.size(); 197 } 198 199 public void startDocument() throws SAXException { 200 document = null; 202 currentElement = null; 203 204 elementStack.clear(); 205 206 if ((elementHandler != null) 207 && (elementHandler instanceof DispatchHandler)) { 208 elementStack.setDispatchHandler((DispatchHandler) elementHandler); 209 } 210 211 namespaceStack.clear(); 212 declaredNamespaceIndex = 0; 213 214 if (mergeAdjacentText && (textBuffer == null)) { 215 textBuffer = new StringBuffer (); 216 } 217 218 textInTextBuffer = false; 219 } 220 221 public void endDocument() throws SAXException { 222 namespaceStack.clear(); 223 elementStack.clear(); 224 currentElement = null; 225 textBuffer = null; 226 } 227 228 public void startElement(String namespaceURI, String localName, 229 String qualifiedName, Attributes attributes) throws SAXException { 230 if (mergeAdjacentText && textInTextBuffer) { 231 completeCurrentTextNode(); 232 } 233 234 QName qName = namespaceStack.getQName(namespaceURI, localName, 235 qualifiedName); 236 237 Branch branch = currentElement; 238 239 if (branch == null) { 240 branch = getDocument(); 241 } 242 243 Element element = branch.addElement(qName); 244 245 addDeclaredNamespaces(element); 247 248 addAttributes(element, attributes); 250 251 elementStack.pushElement(element); 252 currentElement = element; 253 254 entity = null; 256 if (elementHandler != null) { 257 elementHandler.onStart(elementStack); 258 } 259 } 260 261 public void endElement(String namespaceURI, String localName, String qName) 262 throws SAXException { 263 if (mergeAdjacentText && textInTextBuffer) { 264 completeCurrentTextNode(); 265 } 266 267 if ((elementHandler != null) && (currentElement != null)) { 268 elementHandler.onEnd(elementStack); 269 } 270 271 elementStack.popElement(); 272 currentElement = elementStack.peekElement(); 273 } 274 275 public void characters(char[] ch, int start, int end) throws SAXException { 276 if (end == 0) { 277 return; 278 } 279 280 if (currentElement != null) { 281 if (entity != null) { 282 if (mergeAdjacentText && textInTextBuffer) { 283 completeCurrentTextNode(); 284 } 285 286 currentElement.addEntity(entity, new String (ch, start, end)); 287 entity = null; 288 } else if (insideCDATASection) { 289 if (mergeAdjacentText && textInTextBuffer) { 290 completeCurrentTextNode(); 291 } 292 293 cdataText.append(new String (ch, start, end)); 294 } else { 295 if (mergeAdjacentText) { 296 textBuffer.append(ch, start, end); 297 textInTextBuffer = true; 298 } else { 299 currentElement.addText(new String (ch, start, end)); 300 } 301 } 302 } 303 } 304 305 308 318 public void warning(SAXParseException exception) throws SAXException { 319 } 321 322 332 public void error(SAXParseException exception) throws SAXException { 333 throw exception; 334 } 335 336 346 public void fatalError(SAXParseException exception) throws SAXException { 347 throw exception; 348 } 349 350 public void startDTD(String name, String publicId, String systemId) 353 throws SAXException { 354 getDocument().addDocType(name, publicId, systemId); 355 insideDTDSection = true; 356 internalDTDsubset = true; 357 } 358 359 public void endDTD() throws SAXException { 360 insideDTDSection = false; 361 362 DocumentType docType = getDocument().getDocType(); 363 364 if (docType != null) { 365 if (internalDTDDeclarations != null) { 366 docType.setInternalDeclarations(internalDTDDeclarations); 367 } 368 369 if (externalDTDDeclarations != null) { 370 docType.setExternalDeclarations(externalDTDDeclarations); 371 } 372 } 373 374 internalDTDDeclarations = null; 375 externalDTDDeclarations = null; 376 } 377 378 public void startEntity(String name) throws SAXException { 379 ++entityLevel; 380 381 entity = null; 383 384 if (!insideDTDSection) { 385 if (!isIgnorableEntity(name)) { 386 entity = name; 387 } 388 } 389 390 internalDTDsubset = false; 395 } 396 397 public void endEntity(String name) throws SAXException { 398 --entityLevel; 399 entity = null; 400 401 if (entityLevel == 0) { 402 internalDTDsubset = true; 403 } 404 } 405 406 public void startCDATA() throws SAXException { 407 insideCDATASection = true; 408 cdataText = new StringBuffer (); 409 } 410 411 public void endCDATA() throws SAXException { 412 insideCDATASection = false; 413 currentElement.addCDATA(cdataText.toString()); 414 } 415 416 public void comment(char[] ch, int start, int end) throws SAXException { 417 if (!ignoreComments) { 418 if (mergeAdjacentText && textInTextBuffer) { 419 completeCurrentTextNode(); 420 } 421 422 String text = new String (ch, start, end); 423 424 if (!insideDTDSection && (text.length() > 0)) { 425 if (currentElement != null) { 426 currentElement.addComment(text); 427 } else { 428 getDocument().addComment(text); 429 } 430 } 431 } 432 } 433 434 437 457 public void elementDecl(String name, String model) throws SAXException { 458 if (internalDTDsubset) { 459 if (includeInternalDTDDeclarations) { 460 addDTDDeclaration(new ElementDecl(name, model)); 461 } 462 } else { 463 if (includeExternalDTDDeclarations) { 464 addExternalDTDDeclaration(new ElementDecl(name, model)); 465 } 466 } 467 } 468 469 502 public void attributeDecl(String eName, String aName, String type, 503 String valueDefault, String val) throws SAXException { 504 if (internalDTDsubset) { 505 if (includeInternalDTDDeclarations) { 506 addDTDDeclaration(new AttributeDecl(eName, aName, type, 507 valueDefault, val)); 508 } 509 } else { 510 if (includeExternalDTDDeclarations) { 511 addExternalDTDDeclaration(new AttributeDecl(eName, aName, type, 512 valueDefault, val)); 513 } 514 } 515 } 516 517 538 public void internalEntityDecl(String name, String value) 539 throws SAXException { 540 if (internalDTDsubset) { 541 if (includeInternalDTDDeclarations) { 542 addDTDDeclaration(new InternalEntityDecl(name, value)); 543 } 544 } else { 545 if (includeExternalDTDDeclarations) { 546 addExternalDTDDeclaration(new InternalEntityDecl(name, value)); 547 } 548 } 549 } 550 551 573 public void externalEntityDecl(String name, String publicId, String sysId) 574 throws SAXException { 575 ExternalEntityDecl declaration = new ExternalEntityDecl(name, publicId, 576 sysId); 577 578 if (internalDTDsubset) { 579 if (includeInternalDTDDeclarations) { 580 addDTDDeclaration(declaration); 581 } 582 } else { 583 if (includeExternalDTDDeclarations) { 584 addExternalDTDDeclaration(declaration); 585 } 586 } 587 } 588 589 592 624 public void notationDecl(String name, String publicId, String systemId) 625 throws SAXException { 626 } 628 629 658 public void unparsedEntityDecl(String name, String publicId, 659 String systemId, String notationName) throws SAXException { 660 } 662 663 public ElementStack getElementStack() { 666 return elementStack; 667 } 668 669 public void setElementStack(ElementStack elementStack) { 670 this.elementStack = elementStack; 671 } 672 673 public EntityResolver getEntityResolver() { 674 return entityResolver; 675 } 676 677 public void setEntityResolver(EntityResolver entityResolver) { 678 this.entityResolver = entityResolver; 679 } 680 681 public InputSource getInputSource() { 682 return inputSource; 683 } 684 685 public void setInputSource(InputSource inputSource) { 686 this.inputSource = inputSource; 687 } 688 689 695 public boolean isIncludeInternalDTDDeclarations() { 696 return includeInternalDTDDeclarations; 697 } 698 699 707 public void setIncludeInternalDTDDeclarations(boolean include) { 708 this.includeInternalDTDDeclarations = include; 709 } 710 711 717 public boolean isIncludeExternalDTDDeclarations() { 718 return includeExternalDTDDeclarations; 719 } 720 721 729 public void setIncludeExternalDTDDeclarations(boolean include) { 730 this.includeExternalDTDDeclarations = include; 731 } 732 733 738 public boolean isMergeAdjacentText() { 739 return mergeAdjacentText; 740 } 741 742 749 public void setMergeAdjacentText(boolean mergeAdjacentText) { 750 this.mergeAdjacentText = mergeAdjacentText; 751 } 752 753 759 public boolean isStripWhitespaceText() { 760 return stripWhitespaceText; 761 } 762 763 770 public void setStripWhitespaceText(boolean stripWhitespaceText) { 771 this.stripWhitespaceText = stripWhitespaceText; 772 } 773 774 779 public boolean isIgnoreComments() { 780 return ignoreComments; 781 } 782 783 789 public void setIgnoreComments(boolean ignoreComments) { 790 this.ignoreComments = ignoreComments; 791 } 792 793 796 800 protected void completeCurrentTextNode() { 801 if (stripWhitespaceText) { 802 boolean whitespace = true; 803 804 for (int i = 0, size = textBuffer.length(); i < size; i++) { 805 if (!Character.isWhitespace(textBuffer.charAt(i))) { 806 whitespace = false; 807 808 break; 809 } 810 } 811 812 if (!whitespace) { 813 currentElement.addText(textBuffer.toString()); 814 } 815 } else { 816 currentElement.addText(textBuffer.toString()); 817 } 818 819 textBuffer.setLength(0); 820 textInTextBuffer = false; 821 } 822 823 828 protected Document createDocument() { 829 String encoding = getEncoding(); 830 Document doc = documentFactory.createDocument(encoding); 831 832 doc.setEntityResolver(entityResolver); 834 835 if (inputSource != null) { 836 doc.setName(inputSource.getSystemId()); 837 } 838 839 return doc; 840 } 841 842 private String getEncoding() { 843 if (locator == null) { 844 return null; 845 } 846 847 try { 850 Method m = locator.getClass().getMethod("getEncoding", 851 new Class [] {}); 852 853 if (m != null) { 854 return (String ) m.invoke(locator, null); 855 } 856 } catch (Exception e) { 857 } 859 860 return null; 862 } 863 864 872 protected boolean isIgnorableEntity(String name) { 873 return "amp".equals(name) || "apos".equals(name) || "gt".equals(name) 874 || "lt".equals(name) || "quot".equals(name); 875 } 876 877 885 protected void addDeclaredNamespaces(Element element) { 886 Namespace elementNamespace = element.getNamespace(); 887 888 for (int size = namespaceStack.size(); declaredNamespaceIndex < size; 889 declaredNamespaceIndex++) { 890 Namespace namespace = namespaceStack 891 .getNamespace(declaredNamespaceIndex); 892 893 element.add(namespace); 895 896 } 898 } 899 900 908 protected void addAttributes(Element element, Attributes attributes) { 909 boolean noNamespaceAttributes = false; 912 913 if (element instanceof AbstractElement) { 914 AbstractElement baseElement = (AbstractElement) element; 916 baseElement.setAttributes(attributes, namespaceStack, 917 noNamespaceAttributes); 918 } else { 919 int size = attributes.getLength(); 920 921 for (int i = 0; i < size; i++) { 922 String attributeQName = attributes.getQName(i); 923 924 if (noNamespaceAttributes 925 || !attributeQName.startsWith("xmlns")) { 926 String attributeURI = attributes.getURI(i); 927 String attributeLocalName = attributes.getLocalName(i); 928 String attributeValue = attributes.getValue(i); 929 930 QName qName = namespaceStack.getAttributeQName( 931 attributeURI, attributeLocalName, attributeQName); 932 element.addAttribute(qName, attributeValue); 933 } 934 } 935 } 936 } 937 938 944 protected void addDTDDeclaration(Object declaration) { 945 if (internalDTDDeclarations == null) { 946 internalDTDDeclarations = new ArrayList (); 947 } 948 949 internalDTDDeclarations.add(declaration); 950 } 951 952 958 protected void addExternalDTDDeclaration(Object declaration) { 959 if (externalDTDDeclarations == null) { 960 externalDTDDeclarations = new ArrayList (); 961 } 962 963 externalDTDDeclarations.add(declaration); 964 } 965 966 protected ElementStack createElementStack() { 967 return new ElementStack(); 968 } 969 } 970 971 1007 | Popular Tags |