1 package org.webharvest.utils; 2 3 12 14 import java.io.IOException ; 15 import java.io.OutputStreamWriter ; 16 import java.io.Writer ; 17 import java.util.Enumeration ; 18 import java.util.Hashtable ; 19 import java.util.Properties ; 20 21 import org.xml.sax.Attributes ; 22 import org.xml.sax.SAXException ; 23 import org.xml.sax.XMLReader ; 24 import org.xml.sax.helpers.AttributesImpl ; 25 import org.xml.sax.helpers.NamespaceSupport ; 26 import org.xml.sax.helpers.XMLFilterImpl ; 27 import org.xml.sax.ext.LexicalHandler ; 28 29 280 public class XMLWriter extends XMLFilterImpl implements LexicalHandler { 281 282 286 293 public XMLWriter() { 294 init(null); 295 } 296 297 307 public XMLWriter(Writer writer) { 308 init(writer); 309 } 310 311 321 public XMLWriter(XMLReader xmlreader) { 322 super(xmlreader); 323 init(null); 324 } 325 326 339 public XMLWriter(XMLReader xmlreader, Writer writer) { 340 super(xmlreader); 341 init(writer); 342 } 343 344 353 private void init(Writer writer) { 354 setOutput(writer); 355 nsSupport = new NamespaceSupport (); 356 prefixTable = new Hashtable (); 357 forcedDeclTable = new Hashtable (); 358 doneDeclTable = new Hashtable (); 359 outputProperties = new Properties (); 360 } 361 362 366 389 public void reset() { 390 elementLevel = 0; 391 prefixCounter = 0; 392 nsSupport.reset(); 393 } 394 395 411 public void flush() throws IOException { 412 output.flush(); 413 } 414 415 423 public void setOutput(Writer writer) { 424 if (writer == null) { 425 output = new OutputStreamWriter (System.out); 426 } else { 427 output = writer; 428 } 429 } 430 431 448 public void setPrefix(String uri, String prefix) { 449 prefixTable.put(uri, prefix); 450 } 451 452 460 public String getPrefix(String uri) { 461 return (String ) prefixTable.get(uri); 462 } 463 464 484 public void forceNSDecl(String uri) { 485 forcedDeclTable.put(uri, Boolean.TRUE); 486 } 487 488 504 public void forceNSDecl(String uri, String prefix) { 505 setPrefix(uri, prefix); 506 forceNSDecl(uri); 507 } 508 509 513 523 public void startDocument() throws SAXException { 524 reset(); 525 if (!("yes".equals(outputProperties.getProperty(OMIT_XML_DECLARATION, 526 "no")))) 527 write("<?xml version=\"1.0\" standalone=\"yes\"?>\n\n"); 528 super.startDocument(); 529 } 530 531 541 public void endDocument() throws SAXException { 542 write('\n'); 543 super.endDocument(); 544 try { 545 flush(); 546 } catch (IOException e) { 547 throw new SAXException (e); 548 } 549 } 550 551 572 public void startElement(String uri, String localName, String qName, 573 Attributes atts) throws SAXException { 574 elementLevel++; 575 nsSupport.pushContext(); 576 write('<'); 577 writeName(uri, localName, qName, true); 578 writeAttributes(atts); 579 if (elementLevel == 1) { 580 forceNSDecls(); 581 } 582 writeNSDecls(); 583 write('>'); 584 if ("html".equals(outputProperties.getProperty(METHOD, "xml")) 585 && (localName.equals("script") || localName.equals("style"))) { 586 cdataElement = true; 587 } 588 super.startElement(uri, localName, qName, atts); 589 } 590 591 610 public void endElement(String uri, String localName, String qName) 611 throws SAXException { 612 if (!("html".equals(outputProperties.getProperty(METHOD, "xml")) 613 && uri.equals("http://www.w3.org/1999/xhtml") && (localName 614 .equals("area") 615 || localName.equals("base") 616 || localName.equals("basefont") 617 || localName.equals("br") 618 || localName.equals("col") 619 || localName.equals("frame") 620 || localName.equals("hr") 621 || localName.equals("img") 622 || localName.equals("input") 623 || localName.equals("isindex") 624 || localName.equals("link") 625 || localName.equals("meta") || localName.equals("param")))) { 626 write("</"); 627 writeName(uri, localName, qName, true); 628 write('>'); 629 } 630 if (elementLevel == 1) { 631 write('\n'); 632 } 633 cdataElement = false; 634 super.endElement(uri, localName, qName); 635 nsSupport.popContext(); 636 elementLevel--; 637 } 638 639 655 public void characters(char ch[], int start, int len) throws SAXException { 656 if (!cdataElement) { 657 writeEsc(ch, start, len, false); 658 } else { 659 for (int i = start; i < start + len; i++) { 660 write(ch[i]); 661 } 662 } 663 super.characters(ch, start, len); 664 } 665 666 682 public void ignorableWhitespace(char ch[], int start, int length) 683 throws SAXException { 684 writeEsc(ch, start, length, false); 685 super.ignorableWhitespace(ch, start, length); 686 } 687 688 702 public void processingInstruction(String target, String data) 703 throws SAXException { 704 write("<?"); 705 write(target); 706 write(' '); 707 write(data); 708 write("?>"); 709 if (elementLevel < 1) { 710 write('\n'); 711 } 712 super.processingInstruction(target, data); 713 } 714 715 719 746 public void emptyElement(String uri, String localName, String qName, 747 Attributes atts) throws SAXException { 748 nsSupport.pushContext(); 749 write('<'); 750 writeName(uri, localName, qName, true); 751 writeAttributes(atts); 752 if (elementLevel == 1) { 753 forceNSDecls(); 754 } 755 writeNSDecls(); 756 write("/>"); 757 super.startElement(uri, localName, qName, atts); 758 super.endElement(uri, localName, qName); 759 } 760 761 765 783 public void startElement(String uri, String localName) throws SAXException { 784 startElement(uri, localName, "", EMPTY_ATTS); 785 } 786 787 803 public void startElement(String localName) throws SAXException { 804 startElement("", localName, "", EMPTY_ATTS); 805 } 806 807 824 public void endElement(String uri, String localName) throws SAXException { 825 endElement(uri, localName, ""); 826 } 827 828 844 public void endElement(String localName) throws SAXException { 845 endElement("", localName, ""); 846 } 847 848 866 public void emptyElement(String uri, String localName) throws SAXException { 867 emptyElement(uri, localName, "", EMPTY_ATTS); 868 } 869 870 886 public void emptyElement(String localName) throws SAXException { 887 emptyElement("", localName, "", EMPTY_ATTS); 888 } 889 890 922 public void dataElement(String uri, String localName, String qName, 923 Attributes atts, String content) throws SAXException { 924 startElement(uri, localName, qName, atts); 925 characters(content); 926 endElement(uri, localName, qName); 927 } 928 929 958 public void dataElement(String uri, String localName, String content) 959 throws SAXException { 960 dataElement(uri, localName, "", EMPTY_ATTS, content); 961 } 962 963 992 public void dataElement(String localName, String content) 993 throws SAXException { 994 dataElement("", localName, "", EMPTY_ATTS, content); 995 } 996 997 1012 public void characters(String data) throws SAXException { 1013 char ch[] = data.toCharArray(); 1014 characters(ch, 0, ch.length); 1015 } 1016 1017 1021 1027 private void forceNSDecls() { 1028 Enumeration prefixes = forcedDeclTable.keys(); 1029 while (prefixes.hasMoreElements()) { 1030 String prefix = (String ) prefixes.nextElement(); 1031 doPrefix(prefix, null, true); 1032 } 1033 } 1034 1035 1049 private String doPrefix(String uri, String qName, boolean isElement) { 1050 String defaultNS = nsSupport.getURI(""); 1051 if ("".equals(uri)) { 1052 if (isElement && defaultNS != null) 1053 nsSupport.declarePrefix("", ""); 1054 return null; 1055 } 1056 String prefix; 1057 if (isElement && defaultNS != null && uri.equals(defaultNS)) { 1058 prefix = ""; 1059 } else { 1060 prefix = nsSupport.getPrefix(uri); 1061 } 1062 if (prefix != null) { 1063 return prefix; 1064 } 1065 prefix = (String ) doneDeclTable.get(uri); 1066 if (prefix != null 1067 && ((!isElement || defaultNS != null) && "".equals(prefix) || nsSupport 1068 .getURI(prefix) != null)) { 1069 prefix = null; 1070 } 1071 if (prefix == null) { 1072 prefix = (String ) prefixTable.get(uri); 1073 if (prefix != null 1074 && ((!isElement || defaultNS != null) && "".equals(prefix) || nsSupport 1075 .getURI(prefix) != null)) { 1076 prefix = null; 1077 } 1078 } 1079 if (prefix == null && qName != null && !"".equals(qName)) { 1080 int i = qName.indexOf(':'); 1081 if (i == -1) { 1082 if (isElement && defaultNS == null) { 1083 prefix = ""; 1084 } 1085 } else { 1086 prefix = qName.substring(0, i); 1087 } 1088 } 1089 for (; prefix == null || nsSupport.getURI(prefix) != null; prefix = "__NS" 1090 + ++prefixCounter) 1091 ; 1092 nsSupport.declarePrefix(prefix, uri); 1093 doneDeclTable.put(uri, prefix); 1094 return prefix; 1095 } 1096 1097 1106 private void write(char c) throws SAXException { 1107 try { 1108 output.write(c); 1109 } catch (IOException e) { 1110 throw new SAXException (e); 1111 } 1112 } 1113 1114 1122 private void write(String s) throws SAXException { 1123 try { 1124 output.write(s); 1125 } catch (IOException e) { 1126 throw new SAXException (e); 1127 } 1128 } 1129 1130 1142 private void writeAttributes(Attributes atts) throws SAXException { 1143 int len = atts.getLength(); 1144 for (int i = 0; i < len; i++) { 1145 char ch[] = atts.getValue(i).toCharArray(); 1146 write(' '); 1147 writeName(atts.getURI(i), atts.getLocalName(i), atts.getQName(i), 1148 false); 1149 write("=\""); 1150 writeEsc(ch, 0, ch.length, true); 1151 write('"'); 1152 } 1153 } 1154 1155 1170 private void writeEsc(char ch[], int start, int length, boolean isAttVal) 1171 throws SAXException { 1172 for (int i = start; i < start + length; i++) { 1173 switch (ch[i]) { 1174 case '&': 1175 write("&"); 1176 break; 1177 case '<': 1178 write("<"); 1179 break; 1180 case '>': 1181 write(">"); 1182 break; 1183 case '\"': 1184 if (isAttVal) { 1185 write("""); 1186 } else { 1187 write('\"'); 1188 } 1189 break; 1190 default: 1191 write(ch[i]); 1192 } 1193 } 1194 } 1195 1196 1204 private void writeNSDecls() throws SAXException { 1205 Enumeration prefixes = nsSupport.getDeclaredPrefixes(); 1206 while (prefixes.hasMoreElements()) { 1207 String prefix = (String ) prefixes.nextElement(); 1208 String uri = nsSupport.getURI(prefix); 1209 if (uri == null) { 1210 uri = ""; 1211 } 1212 char ch[] = uri.toCharArray(); 1213 write(' '); 1214 if ("".equals(prefix)) { 1215 write("xmlns=\""); 1216 } else { 1217 write("xmlns:"); 1218 write(prefix); 1219 write("=\""); 1220 } 1221 writeEsc(ch, 0, ch.length, true); 1222 write('\"'); 1223 } 1224 } 1225 1226 1242 private void writeName(String uri, String localName, String qName, 1243 boolean isElement) throws SAXException { 1244 String prefix = doPrefix(uri, qName, isElement); 1245 if (prefix != null && !"".equals(prefix)) { 1246 write(prefix); 1247 write(':'); 1248 } 1249 if (localName != null && !"".equals(localName)) { 1250 write(localName); 1251 } else { 1252 int i = qName.indexOf(':'); 1253 write(qName.substring(i + 1, qName.length())); 1254 } 1255 } 1256 1257 1261 public void comment(char[] ch, int start, int length) throws SAXException { 1262 write("<!--"); 1263 for (int i = start; i < start + length; i++) { 1264 write(ch[i]); 1265 if (ch[i] == '-' && i + 1 <= start + length && ch[i + 1] == '-') 1266 write(' '); 1267 } 1268 write("-->"); 1269 } 1270 1271 public void endCDATA() throws SAXException { 1272 } 1273 1274 public void endDTD() throws SAXException { 1275 } 1276 1277 public void endEntity(String name) throws SAXException { 1278 } 1279 1280 public void startCDATA() throws SAXException { 1281 } 1282 1283 public void startDTD(String name, String publicId, String systemId) 1284 throws SAXException { 1285 } 1286 1287 public void startEntity(String name) throws SAXException { 1288 } 1289 1290 1294 public String getOutputProperty(String key) { 1295 return outputProperties.getProperty(key); 1296 } 1297 1298 public void setOutputProperty(String key, String value) { 1299 outputProperties.setProperty(key, value); 1300 } 1301 1302 1306 private final Attributes EMPTY_ATTS = new AttributesImpl (); 1307 1308 public static final String CDATA_SECTION_ELEMENTS = "cdata-section-elements"; 1309 1310 public static final String DOCTYPE_PUBLIC = "doctype-public"; 1311 1312 public static final String DOCTYPE_SYSTEM = "doctype-system"; 1313 1314 public static final String ENCODING = "encoding"; 1315 1316 public static final String INDENT = "indent"; 1317 1318 public static final String MEDIA_TYPE = "media-type"; 1319 1320 public static final String METHOD = "method"; 1321 1322 public static final String OMIT_XML_DECLARATION = "omit-xml-declaration"; 1323 1324 public static final String STANDALONE = "standalone"; 1325 1326 public static final String VERSION = "version"; 1327 1328 1332 private Hashtable prefixTable; 1333 1334 private Hashtable forcedDeclTable; 1335 1336 private Hashtable doneDeclTable; 1337 1338 private int elementLevel = 0; 1339 1340 private Writer output; 1341 1342 private NamespaceSupport nsSupport; 1343 1344 private int prefixCounter = 0; 1345 1346 private Properties outputProperties; 1347 1348 private boolean cdataElement = false; 1349 1350} 1351 1352 | Popular Tags |