1 56 57 package org.jdom.input; 58 59 import java.util.*; 60 61 import org.jdom.*; 62 import org.xml.sax.*; 63 import org.xml.sax.ext.*; 64 import org.xml.sax.helpers.*; 65 66 76 public class SAXHandler extends DefaultHandler implements LexicalHandler, 77 DeclHandler, 78 DTDHandler { 79 80 private static final String CVS_ID = 81 "@(#) $RCSfile: SAXHandler.java,v $ $Revision: 1.71 $ $Date: 2004/12/11 02:18:55 $ $Name: $"; 82 83 84 private static final Map attrNameToTypeMap = new HashMap(13); 85 86 87 private Document document; 88 89 90 private Element currentElement; 91 92 93 private boolean atRoot; 94 95 98 private boolean inDTD = false; 99 100 101 private boolean inInternalSubset = false; 102 103 104 private boolean previousCDATA = false; 105 106 107 private boolean inCDATA = false; 108 109 110 private boolean expand = true; 111 112 114 private boolean suppress = false; 115 116 117 private int entityDepth = 0; 119 121 private List declaredNamespaces; 122 123 124 private StringBuffer internalSubset = new StringBuffer (); 125 126 127 private TextBuffer textBuffer = new TextBuffer(); 128 129 130 private Map externalEntities; 131 132 133 private JDOMFactory factory; 134 135 136 private boolean ignoringWhite = false; 137 138 139 private boolean ignoringBoundaryWhite = false; 140 141 142 private Locator locator; 143 144 160 static { 161 attrNameToTypeMap.put("CDATA", 162 new Integer (Attribute.CDATA_TYPE)); 163 attrNameToTypeMap.put("ID", 164 new Integer (Attribute.ID_TYPE)); 165 attrNameToTypeMap.put("IDREF", 166 new Integer (Attribute.IDREF_TYPE)); 167 attrNameToTypeMap.put("IDREFS", 168 new Integer (Attribute.IDREFS_TYPE)); 169 attrNameToTypeMap.put("ENTITY", 170 new Integer (Attribute.ENTITY_TYPE)); 171 attrNameToTypeMap.put("ENTITIES", 172 new Integer (Attribute.ENTITIES_TYPE)); 173 attrNameToTypeMap.put("NMTOKEN", 174 new Integer (Attribute.NMTOKEN_TYPE)); 175 attrNameToTypeMap.put("NMTOKENS", 176 new Integer (Attribute.NMTOKENS_TYPE)); 177 attrNameToTypeMap.put("NOTATION", 178 new Integer (Attribute.NOTATION_TYPE)); 179 attrNameToTypeMap.put("ENUMERATION", 180 new Integer (Attribute.ENUMERATED_TYPE)); 181 } 182 183 188 public SAXHandler() { 189 this(null); 190 } 191 192 200 public SAXHandler(JDOMFactory factory) { 201 if (factory != null) { 202 this.factory = factory; 203 } else { 204 this.factory = new DefaultJDOMFactory(); 205 } 206 207 atRoot = true; 208 declaredNamespaces = new ArrayList(); 209 externalEntities = new HashMap(); 210 211 document = this.factory.document(null); 212 } 213 214 221 protected void pushElement(Element element) { 222 if (atRoot) { 223 document.setRootElement(element); atRoot = false; 225 } 226 else { 227 factory.addContent(currentElement, element); 228 } 229 currentElement = element; 230 } 231 232 237 public Document getDocument() { 238 return document; 239 } 240 241 249 public JDOMFactory getFactory() { 250 return factory; 251 } 252 253 262 public void setExpandEntities(boolean expand) { 263 this.expand = expand; 264 } 265 266 275 public boolean getExpandEntities() { 276 return expand; 277 } 278 279 290 public void setIgnoringElementContentWhitespace(boolean ignoringWhite) { 291 this.ignoringWhite = ignoringWhite; 292 } 293 294 301 public void setIgnoringBoundaryWhitespace(boolean ignoringBoundaryWhite) { 302 this.ignoringBoundaryWhite = ignoringBoundaryWhite; 303 } 304 305 314 public boolean getIgnoringBoundaryWhitespace() { 315 return ignoringBoundaryWhite; 316 } 317 318 328 public boolean getIgnoringElementContentWhitespace() { 329 return ignoringWhite; 330 } 331 332 public void startDocument() { 333 if (locator != null) { 334 document.setBaseURI(locator.getSystemId()); 335 } 336 } 337 338 347 public void externalEntityDecl(String name, 348 String publicID, String systemID) 349 throws SAXException { 350 externalEntities.put(name, new String []{publicID, systemID}); 352 353 if (!inInternalSubset) return; 354 355 internalSubset.append(" <!ENTITY ") 356 .append(name); 357 appendExternalId(publicID, systemID); 358 internalSubset.append(">\n"); 359 } 360 361 371 public void attributeDecl(String eName, String aName, String type, 372 String valueDefault, String value) 373 throws SAXException { 374 375 if (!inInternalSubset) return; 376 377 internalSubset.append(" <!ATTLIST ") 378 .append(eName) 379 .append(' ') 380 .append(aName) 381 .append(' ') 382 .append(type) 383 .append(' '); 384 if (valueDefault != null) { 385 internalSubset.append(valueDefault); 386 } else { 387 internalSubset.append('\"') 388 .append(value) 389 .append('\"'); 390 } 391 if ((valueDefault != null) && (valueDefault.equals("#FIXED"))) { 392 internalSubset.append(" \"") 393 .append(value) 394 .append('\"'); 395 } 396 internalSubset.append(">\n"); 397 } 398 399 406 public void elementDecl(String name, String model) throws SAXException { 407 if (!inInternalSubset) return; 409 410 internalSubset.append(" <!ELEMENT ") 411 .append(name) 412 .append(' ') 413 .append(model) 414 .append(">\n"); 415 } 416 417 424 public void internalEntityDecl(String name, String value) 425 throws SAXException { 426 427 if (!inInternalSubset) return; 429 430 internalSubset.append(" <!ENTITY "); 431 if (name.startsWith("%")) { 432 internalSubset.append("% ").append(name.substring(1)); 433 } else { 434 internalSubset.append(name); 435 } 436 internalSubset.append(" \"") 437 .append(value) 438 .append("\">\n"); 439 } 440 441 452 public void processingInstruction(String target, String data) 453 throws SAXException { 454 455 if (suppress) return; 456 457 flushCharacters(); 458 459 if (atRoot) { 460 factory.addContent(document, factory.processingInstruction(target, data)); 461 } else { 462 factory.addContent(getCurrentElement(), 463 factory.processingInstruction(target, data)); 464 } 465 } 466 467 475 public void skippedEntity(String name) 476 throws SAXException { 477 478 if (name.startsWith("%")) return; 480 481 flushCharacters(); 482 483 factory.addContent(getCurrentElement(), factory.entityRef(name)); 484 } 485 486 493 public void startPrefixMapping(String prefix, String uri) 494 throws SAXException { 495 496 if (suppress) return; 497 498 Namespace ns = Namespace.getNamespace(prefix, uri); 499 declaredNamespaces.add(ns); 500 } 501 502 519 public void startElement(String namespaceURI, String localName, 520 String qName, Attributes atts) 521 throws SAXException { 522 if (suppress) return; 523 524 Element element = null; 525 526 if ((namespaceURI != null) && (!namespaceURI.equals(""))) { 527 String prefix = ""; 528 529 if (!qName.equals(localName)) { 531 int split = qName.indexOf(":"); 532 prefix = qName.substring(0, split); 533 } 534 Namespace elementNamespace = 535 Namespace.getNamespace(prefix, namespaceURI); 536 element = factory.element(localName, elementNamespace); 537 } else { 538 element = factory.element(localName); 539 } 540 541 if (declaredNamespaces.size() > 0) { 544 transferNamespaces(element); 545 } 546 547 for (int i=0, len=atts.getLength(); i<len; i++) { 549 Attribute attribute = null; 550 551 String attLocalName = atts.getLocalName(i); 552 String attQName = atts.getQName(i); 553 int attType = getAttributeType(atts.getType(i)); 554 555 if (attQName.startsWith("xmlns:") || attQName.equals("xmlns")) { 560 continue; 561 } 562 563 if (!attQName.equals(attLocalName)) { 564 String attPrefix = attQName.substring(0, attQName.indexOf(":")); 565 Namespace attNs = Namespace.getNamespace(attPrefix, 566 atts.getURI(i)); 567 568 attribute = factory.attribute(attLocalName, atts.getValue(i), 569 attType, attNs); 570 } else { 571 attribute = factory.attribute(attLocalName, atts.getValue(i), 572 attType); 573 } 574 factory.setAttribute(element, attribute); 575 } 576 577 flushCharacters(); 578 579 if (atRoot) { 580 document.setRootElement(element); atRoot = false; 582 } else { 583 factory.addContent(getCurrentElement(), element); 584 } 585 currentElement = element; 586 } 587 588 594 private void transferNamespaces(Element element) { 595 Iterator i = declaredNamespaces.iterator(); 596 while (i.hasNext()) { 597 Namespace ns = (Namespace)i.next(); 598 if (ns != element.getNamespace()) { 599 element.addNamespaceDeclaration(ns); 600 } 601 } 602 declaredNamespaces.clear(); 603 } 604 605 613 public void characters(char[] ch, int start, int length) 614 throws SAXException { 615 616 if (suppress || (length == 0)) 617 return; 618 619 if (previousCDATA != inCDATA) { 620 flushCharacters(); 621 } 622 623 textBuffer.append(ch, start, length); 624 } 625 626 636 public void ignorableWhitespace(char[] ch, int start, int length) 637 throws SAXException { 638 if (!ignoringWhite) { 639 characters(ch, start, length); 640 } 641 } 642 643 649 protected void flushCharacters() throws SAXException { 650 if (ignoringBoundaryWhite) { 651 if (!textBuffer.isAllWhitespace()) { 652 flushCharacters(textBuffer.toString()); 653 } 654 } 655 else { 656 flushCharacters(textBuffer.toString()); 657 } 658 textBuffer.clear(); 659 } 660 661 668 protected void flushCharacters(String data) throws SAXException { 669 if (data.length() == 0) { 670 previousCDATA = inCDATA; 671 return; 672 } 673 674 684 685 if (previousCDATA) { 686 factory.addContent(getCurrentElement(), factory.cdata(data)); 687 } 688 else { 689 factory.addContent(getCurrentElement(), factory.text(data)); 690 } 691 692 previousCDATA = inCDATA; 693 } 694 695 707 public void endElement(String namespaceURI, String localName, 708 String qName) throws SAXException { 709 710 if (suppress) return; 711 712 flushCharacters(); 713 714 if (!atRoot) { 715 Parent p = currentElement.getParent(); 716 if (p instanceof Document) { 717 atRoot = true; 718 } 719 else { 720 currentElement = (Element) p; 721 } 722 } 723 else { 724 throw new SAXException( 725 "Ill-formed XML document (missing opening tag for " + 726 localName + ")"); 727 } 728 } 729 730 740 public void startDTD(String name, String publicID, String systemID) 741 throws SAXException { 742 743 flushCharacters(); 745 factory.addContent(document, factory.docType(name, publicID, systemID)); 746 inDTD = true; 747 inInternalSubset = true; 748 } 749 750 755 public void endDTD() throws SAXException { 756 757 document.getDocType().setInternalSubset(internalSubset.toString()); 758 inDTD = false; 759 inInternalSubset = false; 760 } 761 762 public void startEntity(String name) throws SAXException { 763 entityDepth++; 764 765 if (expand || entityDepth > 1) { 766 return; 768 } 769 770 if (name.equals("[dtd]")) { 772 inInternalSubset = false; 773 return; 774 } 775 776 if ((!inDTD) && 778 (!name.equals("amp")) && 779 (!name.equals("lt")) && 780 (!name.equals("gt")) && 781 (!name.equals("apos")) && 782 (!name.equals("quot"))) { 783 784 if (!expand) { 785 String pub = null; 786 String sys = null; 787 String [] ids = (String []) externalEntities.get(name); 788 if (ids != null) { 789 pub = ids[0]; sys = ids[1]; } 792 799 if (!atRoot) { 800 flushCharacters(); 801 EntityRef entity = factory.entityRef(name, pub, sys); 802 803 factory.addContent(getCurrentElement(), entity); 805 } 806 suppress = true; 807 } 808 } 809 } 810 811 public void endEntity(String name) throws SAXException { 812 entityDepth--; 813 if (entityDepth == 0) { 814 suppress = false; 817 } 818 if (name.equals("[dtd]")) { 819 inInternalSubset = true; 820 } 821 } 822 823 828 public void startCDATA() throws SAXException { 829 if (suppress) return; 830 831 inCDATA = true; 832 } 833 834 837 public void endCDATA() throws SAXException { 838 if (suppress) return; 839 840 previousCDATA = true; 841 inCDATA = false; 842 } 843 844 855 public void comment(char[] ch, int start, int length) 856 throws SAXException { 857 858 if (suppress) return; 859 860 flushCharacters(); 861 862 String commentText = new String (ch, start, length); 863 if (inDTD && inInternalSubset && (expand == false)) { 864 internalSubset.append(" <!--") 865 .append(commentText) 866 .append("-->\n"); 867 return; 868 } 869 if ((!inDTD) && (!commentText.equals(""))) { 870 if (atRoot) { 871 factory.addContent(document, factory.comment(commentText)); 872 } else { 873 factory.addContent(getCurrentElement(), factory.comment(commentText)); 874 } 875 } 876 } 877 878 885 public void notationDecl(String name, String publicID, String systemID) 886 throws SAXException { 887 888 if (!inInternalSubset) return; 889 890 internalSubset.append(" <!NOTATION ") 891 .append(name); 892 appendExternalId(publicID, systemID); 893 internalSubset.append(">\n"); 894 } 895 896 904 public void unparsedEntityDecl(String name, String publicID, 905 String systemID, String notationName) 906 throws SAXException { 907 908 if (!inInternalSubset) return; 909 910 internalSubset.append(" <!ENTITY ") 911 .append(name); 912 appendExternalId(publicID, systemID); 913 internalSubset.append(" NDATA ") 914 .append(notationName); 915 internalSubset.append(">\n"); 916 } 917 918 925 private void appendExternalId(String publicID, String systemID) { 926 if (publicID != null) { 927 internalSubset.append(" PUBLIC \"") 928 .append(publicID) 929 .append('\"'); 930 } 931 if (systemID != null) { 932 if (publicID == null) { 933 internalSubset.append(" SYSTEM "); 934 } 935 else { 936 internalSubset.append(' '); 937 } 938 internalSubset.append('\"') 939 .append(systemID) 940 .append('\"'); 941 } 942 } 943 944 950 public Element getCurrentElement() throws SAXException { 951 if (currentElement == null) { 952 throw new SAXException( 953 "Ill-formed XML document (multiple root elements detected)"); 954 } 955 return currentElement; 956 } 957 958 970 private static int getAttributeType(String typeName) { 971 Integer type = (Integer )(attrNameToTypeMap.get(typeName)); 972 if (type == null) { 973 if (typeName != null && typeName.length() > 0 && 974 typeName.charAt(0) == '(') { 975 return Attribute.ENUMERATED_TYPE; 979 } 980 else { 981 return Attribute.UNDECLARED_TYPE; 982 } 983 } else { 984 return type.intValue(); 985 } 986 } 987 988 1000 public void setDocumentLocator(Locator locator) { 1001 this.locator = locator; 1002 } 1003 1004 1011 public Locator getDocumentLocator() { 1012 return locator; 1013 } 1014} 1015 | Popular Tags |