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 endPrefixMapping(NamespaceStack namespaces, 980 int previouslyDeclaredNamespaces) 981 throws JDOMException { 982 while (namespaces.size() > previouslyDeclaredNamespaces) { 983 String prefix = namespaces.pop(); 984 try { 985 contentHandler.endPrefixMapping(prefix); 986 } 987 catch (SAXException se) { 988 throw new JDOMException("Exception in endPrefixMapping", se); 989 } 990 } 991 } 992 993 1003 private void startElement(Element element, Attributes nsAtts) 1004 throws JDOMException { 1005 String namespaceURI = element.getNamespaceURI(); 1006 String localName = element.getName(); 1007 String rawName = element.getQualifiedName(); 1008 1009 AttributesImpl atts = (nsAtts != null)? 1011 new AttributesImpl(nsAtts): new AttributesImpl(); 1012 1013 List attributes = element.getAttributes(); 1014 Iterator i = attributes.iterator(); 1015 while (i.hasNext()) { 1016 Attribute a = (Attribute) i.next(); 1017 atts.addAttribute(a.getNamespaceURI(), 1018 a.getName(), 1019 a.getQualifiedName(), 1020 getAttributeTypeName(a.getAttributeType()), 1021 a.getValue()); 1022 } 1023 1024 try { 1025 contentHandler.startElement(namespaceURI, localName, rawName, atts); 1026 } 1027 catch (SAXException se) { 1028 throw new JDOMException("Exception in startElement", se); 1029 } 1030 } 1031 1032 1040 private void endElement(Element element) throws JDOMException { 1041 String namespaceURI = element.getNamespaceURI(); 1042 String localName = element.getName(); 1043 String rawName = element.getQualifiedName(); 1044 1045 try { 1046 contentHandler.endElement(namespaceURI, localName, rawName); 1047 } 1048 catch (SAXException se) { 1049 throw new JDOMException("Exception in endElement", se); 1050 } 1051 } 1052 1053 1061 private void elementContent(List content, NamespaceStack namespaces) 1062 throws JDOMException { 1063 for (Iterator i=content.iterator(); i.hasNext(); ) { 1064 Object obj = i.next(); 1065 1066 if (obj instanceof Content) { 1067 this.elementContent((Content)obj, namespaces); 1068 } 1069 else { 1070 handleError(new JDOMException( 1074 "Invalid element content: " + obj)); 1075 } 1076 } 1077 } 1078 1079 1087 private void elementContent(Content node, NamespaceStack namespaces) 1088 throws JDOMException { 1089 locator.setNode(node); 1091 1092 if (node instanceof Element) { 1093 element((Element) node, namespaces); 1094 } 1095 else if (node instanceof CDATA) { 1096 cdata(((CDATA) node).getText()); 1097 } 1098 else if (node instanceof Text) { 1099 characters(((Text) node).getText()); 1101 } 1102 else if (node instanceof ProcessingInstruction) { 1103 processingInstruction((ProcessingInstruction) node); 1105 } 1106 else if (node instanceof Comment) { 1107 comment(((Comment) node).getText()); 1109 } 1110 else if (node instanceof EntityRef) { 1111 entityRef((EntityRef) node); 1113 } 1114 else { 1115 handleError(new JDOMException("Invalid element content: " + node)); 1119 } 1120 } 1121 1122 1129 private void cdata(String cdataText) throws JDOMException { 1130 try { 1131 if (lexicalHandler != null) { 1132 lexicalHandler.startCDATA(); 1133 characters(cdataText); 1134 lexicalHandler.endCDATA(); 1135 } 1136 else { 1137 characters(cdataText); 1138 } 1139 } 1140 catch (SAXException se) { 1141 throw new JDOMException("Exception in CDATA", se); 1142 } 1143 } 1144 1145 1152 private void characters(String elementText) throws JDOMException { 1153 char[] c = elementText.toCharArray(); 1154 try { 1155 contentHandler.characters(c, 0, c.length); 1156 } 1157 catch (SAXException se) { 1158 throw new JDOMException("Exception in characters", se); 1159 } 1160 } 1161 1162 1169 private void comment(String commentText) throws JDOMException { 1170 if (lexicalHandler != null) { 1171 char[] c = commentText.toCharArray(); 1172 try { 1173 lexicalHandler.comment(c, 0, c.length); 1174 } catch (SAXException se) { 1175 throw new JDOMException("Exception in comment", se); 1176 } 1177 } 1178 } 1179 1180 1188 private void entityRef(EntityRef entity) throws JDOMException { 1189 if (entity != null) { 1190 try { 1191 contentHandler.skippedEntity(entity.getName()); 1194 } 1195 catch (SAXException se) { 1196 throw new JDOMException("Exception in entityRef", se); 1197 } 1198 } 1199 } 1200 1201 1202 1213 private AttributesImpl addNsAttribute(AttributesImpl atts, Namespace ns) { 1214 if (this.declareNamespaces) { 1215 if (atts == null) { 1216 atts = new AttributesImpl(); 1217 } 1218 1219 String prefix = ns.getPrefix(); 1220 if (prefix.equals("")) { 1221 atts.addAttribute("", "", "xmlns", "CDATA", ns.getURI()); } 1227 else { 1228 atts.addAttribute("", "", "xmlns:" + ns.getPrefix(), "CDATA", ns.getURI()); } 1234 } 1235 return atts; 1236 } 1237 1238 1251 private static String getAttributeTypeName(int type) { 1252 if ((type < 0) || (type >= attrTypeToNameMap.length)) { 1253 type = Attribute.UNDECLARED_TYPE; 1254 } 1255 return attrTypeToNameMap[type]; 1256 } 1257 1258 1274 private void handleError(JDOMException exception) throws JDOMException { 1275 if (errorHandler != null) { 1276 try { 1277 errorHandler.error(new SAXParseException( 1278 exception.getMessage(), null, exception)); 1279 } 1280 catch (SAXException se) { 1281 if (se.getException() instanceof JDOMException) { 1282 throw (JDOMException)(se.getException()); 1283 } 1284 else { 1285 throw new JDOMException(se.getMessage(), se); 1286 } 1287 } 1288 } 1289 else { 1290 throw exception; 1291 } 1292 } 1293 1294 1303 protected XMLReader createParser() throws Exception { 1304 XMLReader parser = null; 1305 1306 try { 1311 Class factoryClass = 1312 Class.forName("javax.xml.parsers.SAXParserFactory"); 1313 1314 Method newParserInstance = 1316 factoryClass.getMethod("newInstance", null); 1317 Object factory = newParserInstance.invoke(null, null); 1318 1319 Method newSAXParser = factoryClass.getMethod("newSAXParser", null); 1321 Object jaxpParser = newSAXParser.invoke(factory, null); 1322 1323 Class parserClass = jaxpParser.getClass(); 1325 Method getXMLReader = 1326 parserClass.getMethod("getXMLReader", null); 1327 parser = (XMLReader)getXMLReader.invoke(jaxpParser, null); 1328 } catch (ClassNotFoundException e) { 1329 } catch (InvocationTargetException e) { 1331 } catch (NoSuchMethodException e) { 1333 } catch (IllegalAccessException e) { 1335 } 1337 1338 if (parser == null) { 1341 parser = XMLReaderFactory.createXMLReader( 1342 "org.apache.xerces.parsers.SAXParser"); 1343 } 1344 return parser; 1345 } 1346 1347 1358 private XMLReader createDTDParser() throws JDOMException { 1359 XMLReader parser = null; 1360 1361 try 1363 { 1364 parser = createParser(); 1365 } 1366 catch (Exception ex1) { 1367 throw new JDOMException("Error in SAX parser allocation", ex1); 1368 } 1369 1370 if (this.getDTDHandler() != null) { 1372 parser.setDTDHandler(this.getDTDHandler()); 1373 } 1374 if (this.getEntityResolver() != null) { 1375 parser.setEntityResolver(this.getEntityResolver()); 1376 } 1377 if (this.getLexicalHandler() != null) { 1378 try { 1379 parser.setProperty(LEXICAL_HANDLER_SAX_PROPERTY, 1380 this.getLexicalHandler()); 1381 } 1382 catch (SAXException ex1) { 1383 try { 1384 parser.setProperty(LEXICAL_HANDLER_ALT_PROPERTY, 1385 this.getLexicalHandler()); 1386 } catch (SAXException ex2) { 1387 } 1389 } 1390 } 1391 if (this.getDeclHandler() != null) { 1392 try { 1393 parser.setProperty(DECL_HANDLER_SAX_PROPERTY, 1394 this.getDeclHandler()); 1395 } 1396 catch (SAXException ex1) { 1397 try { 1398 parser.setProperty(DECL_HANDLER_ALT_PROPERTY, 1399 this.getDeclHandler()); 1400 } catch (SAXException ex2) { 1401 } 1403 } 1404 } 1405 1406 parser.setErrorHandler(new DefaultHandler()); 1408 1409 return parser; 1410 } 1411 1412 1432 public JDOMLocator getLocator() { 1433 return (locator != null)? new JDOMLocator(locator): null; 1434 } 1435} 1436 | Popular Tags |