| 1 10 12 package org.ccil.cowan.tagsoup; 13 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 30 248 public class XMLWriter extends XMLFilterImpl implements LexicalHandler  249 { 250 251 252 256 257 262 public XMLWriter () 263 { 264 init(null); 265 } 266 267 268 276 public XMLWriter (Writer writer) 277 { 278 init(writer); 279 } 280 281 282 290 public XMLWriter (XMLReader xmlreader) 291 { 292 super(xmlreader); 293 init(null); 294 } 295 296 297 308 public XMLWriter (XMLReader xmlreader, Writer writer) 309 { 310 super(xmlreader); 311 init(writer); 312 } 313 314 315 323 private void init (Writer writer) 324 { 325 setOutput(writer); 326 nsSupport = new NamespaceSupport (); 327 prefixTable = new Hashtable (); 328 forcedDeclTable = new Hashtable (); 329 doneDeclTable = new Hashtable (); 330 outputProperties = new Properties (); 331 } 332 333 334 335 339 340 359 public void reset () 360 { 361 elementLevel = 0; 362 prefixCounter = 0; 363 nsSupport.reset(); 364 } 365 366 367 381 public void flush () 382 throws IOException 383 { 384 output.flush(); 385 } 386 387 388 396 public void setOutput (Writer writer) 397 { 398 if (writer == null) { 399 output = new OutputStreamWriter (System.out); 400 } else { 401 output = writer; 402 } 403 } 404 405 406 420 public void setPrefix (String uri, String prefix) 421 { 422 prefixTable.put(uri, prefix); 423 } 424 425 426 433 public String getPrefix (String uri) 434 { 435 return (String )prefixTable.get(uri); 436 } 437 438 439 455 public void forceNSDecl (String uri) 456 { 457 forcedDeclTable.put(uri, Boolean.TRUE); 458 } 459 460 461 474 public void forceNSDecl (String uri, String prefix) 475 { 476 setPrefix(uri, prefix); 477 forceNSDecl(uri); 478 } 479 480 481 482 486 487 497 public void startDocument () 498 throws SAXException  499 { 500 reset(); 501 if (!("yes".equals(outputProperties.getProperty(OMIT_XML_DECLARATION, "no")))) { 502 write("<?xml version=\"1.0\""); 503 if (outputEncoding != null && outputEncoding != "") { 504 write(" encoding=\""); 505 write(outputEncoding); 506 write("\""); 507 } 508 write(" standalone=\"yes\"?>\n"); 509 } 510 super.startDocument(); 511 } 512 513 514 524 public void endDocument () 525 throws SAXException  526 { 527 write('\n'); 528 super.endDocument(); 529 try { 530 flush(); 531 } catch (IOException e) { 532 throw new SAXException (e); 533 } 534 } 535 536 537 556 public void startElement (String uri, String localName, 557 String qName, Attributes atts) 558 throws SAXException  559 { 560 elementLevel++; 561 nsSupport.pushContext(); 562 write('<'); 563 writeName(uri, localName, qName, true); 564 writeAttributes(atts); 565 if (elementLevel == 1) { 566 forceNSDecls(); 567 } 568 writeNSDecls(); 569 write('>'); 570 if (htmlMode && (qName.equals("script") || qName.equals("style"))) { 572 cdataElement = true; 573 } 575 super.startElement(uri, localName, qName, atts); 576 } 577 578 579 597 public void endElement (String uri, String localName, String qName) 598 throws SAXException  599 { 600 if (!(htmlMode && 601 (uri.equals("http://www.w3.org/1999/xhtml") || 602 uri.equals("")) && 603 (qName.equals("area") || qName.equals("base") || 604 qName.equals("basefont") || qName.equals("br") || 605 qName.equals("col") || qName.equals("frame") || 606 qName.equals("hr") || qName.equals("img") || 607 qName.equals("input") || qName.equals("isindex") || 608 qName.equals("link") || qName.equals("meta") || 609 qName.equals("param")))) { 610 write("</"); 611 writeName(uri, localName, qName, true); 612 write('>'); 613 } 614 if (elementLevel == 1) { 615 write('\n'); 616 } 617 cdataElement = false; 618 super.endElement(uri, localName, qName); 619 nsSupport.popContext(); 620 elementLevel--; 621 } 622 623 624 637 public void characters (char ch[], int start, int len) 638 throws SAXException  639 { 640 if (!cdataElement) { 641 writeEsc(ch, start, len, false); 642 } 643 else { 644 for (int i = start; i < start + len; i++) { 645 write(ch[i]); 646 } 647 } 648 super.characters(ch, start, len); 649 } 650 651 652 665 public void ignorableWhitespace (char ch[], int start, int length) 666 throws SAXException  667 { 668 writeEsc(ch, start, length, false); 669 super.ignorableWhitespace(ch, start, length); 670 } 671 672 673 674 686 public void processingInstruction (String target, String data) 687 throws SAXException  688 { 689 write("<?"); 690 write(target); 691 write(' '); 692 write(data); 693 write("?>"); 694 if (elementLevel < 1) { 695 write('\n'); 696 } 697 super.processingInstruction(target, data); 698 } 699 700 701 702 706 730 public void emptyElement (String uri, String localName, 731 String qName, Attributes atts) 732 throws SAXException  733 { 734 nsSupport.pushContext(); 735 write('<'); 736 writeName(uri, localName, qName, true); 737 writeAttributes(atts); 738 if (elementLevel == 1) { 739 forceNSDecls(); 740 } 741 writeNSDecls(); 742 write("/>"); 743 super.startElement(uri, localName, qName, atts); 744 super.endElement(uri, localName, qName); 745 } 746 747 748 749 753 754 755 771 public void startElement (String uri, String localName) 772 throws SAXException  773 { 774 startElement(uri, localName, "", EMPTY_ATTS); 775 } 776 777 778 793 public void startElement (String localName) 794 throws SAXException  795 { 796 startElement("", localName, "", EMPTY_ATTS); 797 } 798 799 800 814 public void endElement (String uri, String localName) 815 throws SAXException  816 { 817 endElement(uri, localName, ""); 818 } 819 820 821 835 public void endElement (String localName) 836 throws SAXException  837 { 838 endElement("", localName, ""); 839 } 840 841 842 857 public void emptyElement (String uri, String localName) 858 throws SAXException  859 { 860 emptyElement(uri, localName, "", EMPTY_ATTS); 861 } 862 863 864 879 public void emptyElement (String localName) 880 throws SAXException  881 { 882 emptyElement("", localName, "", EMPTY_ATTS); 883 } 884 885 886 911 public void dataElement (String uri, String localName, 912 String qName, Attributes atts, 913 String content) 914 throws SAXException  915 { 916 startElement(uri, localName, qName, atts); 917 characters(content); 918 endElement(uri, localName, qName); 919 } 920 921 922 946 public void dataElement (String uri, String localName, String content) 947 throws SAXException  948 { 949 dataElement(uri, localName, "", EMPTY_ATTS, content); 950 } 951 952 953 977 public void dataElement (String localName, String content) 978 throws SAXException  979 { 980 dataElement("", localName, "", EMPTY_ATTS, content); 981 } 982 983 984 997 public void characters (String data) 998 throws SAXException  999 { 1000 char ch[] = data.toCharArray(); 1001 characters(ch, 0, ch.length); 1002 } 1003 1004 1005 1006 1010 1011 1017 private void forceNSDecls () 1018 { 1019 Enumeration prefixes = forcedDeclTable.keys(); 1020 while (prefixes.hasMoreElements()) { 1021 String prefix = (String )prefixes.nextElement(); 1022 doPrefix(prefix, null, true); 1023 } 1024 } 1025 1026 1027 1040 private String doPrefix (String uri, String qName, boolean isElement) 1041 { 1042 String defaultNS = nsSupport.getURI(""); 1043 if ("".equals(uri)) { 1044 if (isElement && defaultNS != null) 1045 nsSupport.declarePrefix("", ""); 1046 return null; 1047 } 1048 String prefix; 1049 if (isElement && defaultNS != null && uri.equals(defaultNS)) { 1050 prefix = ""; 1051 } else { 1052 prefix = nsSupport.getPrefix(uri); 1053 } 1054 if (prefix != null) { 1055 return prefix; 1056 } 1057 prefix = (String ) doneDeclTable.get(uri); 1058 if (prefix != null && 1059 ((!isElement || defaultNS != null) && 1060 "".equals(prefix) || nsSupport.getURI(prefix) != null)) { 1061 prefix = null; 1062 } 1063 if (prefix == null) { 1064 prefix = (String ) prefixTable.get(uri); 1065 if (prefix != null && 1066 ((!isElement || defaultNS != null) && 1067 "".equals(prefix) || nsSupport.getURI(prefix) != null)) { 1068 prefix = null; 1069 } 1070 } 1071 if (prefix == null && qName != null && !"".equals(qName)) { 1072 int i = qName.indexOf(':'); 1073 if (i == -1) { 1074 if (isElement && defaultNS == null) { 1075 prefix = ""; 1076 } 1077 } else { 1078 prefix = qName.substring(0, i); 1079 } 1080 } 1081 for (; 1082 prefix == null || nsSupport.getURI(prefix) != null; 1083 prefix = "__NS" + ++prefixCounter) 1084 ; 1085 nsSupport.declarePrefix(prefix, uri); 1086 doneDeclTable.put(uri, prefix); 1087 return prefix; 1088 } 1089 1090 1091 1099 private void write (char c) 1100 throws SAXException  1101 { 1102 try { 1103 output.write(c); 1104 } catch (IOException e) { 1105 throw new SAXException (e); 1106 } 1107 } 1108 1109 1110 1118 private void write (String s) 1119 throws SAXException  1120 { 1121 try { 1122 output.write(s); 1123 } catch (IOException e) { 1124 throw new SAXException (e); 1125 } 1126 } 1127 1128 1129 1139 private void writeAttributes (Attributes atts) 1140 throws SAXException  1141 { 1142 int len = atts.getLength(); 1143 for (int i = 0; i < len; i++) { 1144 char ch[] = atts.getValue(i).toCharArray(); 1145 write(' '); 1146 writeName(atts.getURI(i), atts.getLocalName(i), 1147 atts.getQName(i), false); 1148 write("=\""); 1149 writeEsc(ch, 0, ch.length, true); 1150 write('"'); 1151 } 1152 } 1153 1154 1155 1166 private void writeEsc (char ch[], int start, 1167 int length, boolean isAttVal) 1168 throws SAXException  1169 { 1170 for (int i = start; i < start + length; i++) { 1171 switch (ch[i]) { 1172 case '&': 1173 write("&"); 1174 break; 1175 case '<': 1176 write("<"); 1177 break; 1178 case '>': 1179 write(">"); 1180 break; 1181 case '\"': 1182 if (isAttVal) { 1183 write("""); 1184 } else { 1185 write('\"'); 1186 } 1187 break; 1188 default: 1189 if (!unicodeMode && ch[i] > '\u007f') { 1190 write("&#"); 1191 write(Integer.toString(ch[i])); 1192 write(';'); 1193 } else { 1194 write(ch[i]); 1195 } 1196 } 1197 } 1198 } 1199 1200 1201 1209 private void writeNSDecls () 1210 throws SAXException  1211 { 1212 Enumeration prefixes = nsSupport.getDeclaredPrefixes(); 1213 while (prefixes.hasMoreElements()) { 1214 String prefix = (String ) prefixes.nextElement(); 1215 String uri = nsSupport.getURI(prefix); 1216 if (uri == null) { 1217 uri = ""; 1218 } 1219 char ch[] = uri.toCharArray(); 1220 write(' '); 1221 if ("".equals(prefix)) { 1222 write("xmlns=\""); 1223 } else { 1224 write("xmlns:"); 1225 write(prefix); 1226 write("=\""); 1227 } 1228 writeEsc(ch, 0, ch.length, true); 1229 write('\"'); 1230 } 1231 } 1232 1233 1234 1246 private void writeName (String uri, String localName, 1247 String qName, boolean isElement) 1248 throws SAXException  1249 { 1250 String prefix = doPrefix(uri, qName, isElement); 1251 if (prefix != null && !"".equals(prefix)) { 1252 write(prefix); 1253 write(':'); 1254 } 1255 if (localName != null && !"".equals(localName)) { 1256 write(localName); 1257 } else { 1258 int i = qName.indexOf(':'); 1259 write(qName.substring(i + 1, qName.length())); 1260 } 1261 } 1262 1263 1264 1265 1269 public void comment(char[] ch, int start, int length) throws SAXException  1270 { 1271 write("<!--"); 1272 for (int i = start; i < start + length; i++) { 1273 write(ch[i]); 1274 if (ch[i] == '-' && i + 1 <= start + length && ch[i+1] == '-') 1275 write(' '); 1276 } 1277 write("-->"); 1278 } 1279 1280 public void endCDATA() throws SAXException { } 1281 public void endDTD() throws SAXException { } 1282 public void endEntity(String name) throws SAXException { } 1283 public void startCDATA() throws SAXException { } 1284 public void startDTD(String name, String publicid, String systemid) throws SAXException { 1285 if (name == null) return; write("<!DOCTYPE "); 1287 if (systemid == null) systemid = ""; 1288 char sysquote = (systemid.indexOf('"') != -1) ? '\'': '"'; 1289 write(name); 1290 if (!(publicid == null || "".equals(publicid))) { 1291 char pubquote = (publicid.indexOf('"') != -1) ? '\'': '"'; 1292 write(" PUBLIC "); 1293 write(pubquote); 1294 write(publicid); 1295 write(pubquote); 1296 write(' '); 1297 } 1298 else { 1299 write(" SYSTEM "); 1300 } 1301 write(sysquote); 1302 write(systemid); 1303 write(sysquote); 1304 write(">\n"); 1305 } 1306 1307 public void startEntity(String name) throws SAXException { } 1308 1309 1310 1314 public String getOutputProperty(String key) { 1315 return outputProperties.getProperty(key); 1316 } 1317 1318 public void setOutputProperty(String key, String value) { 1319 outputProperties.setProperty(key, value); 1320 if (key.equals(ENCODING)) { 1322 outputEncoding = value; 1323 unicodeMode = value.substring(0, 3).equalsIgnoreCase("utf"); 1324 } 1326 if (key.equals(METHOD)) { 1327 htmlMode = value.equals("html"); 1328 } 1329 } 1331 1332 1333 1337 private final Attributes EMPTY_ATTS = new AttributesImpl(); 1338 public static final String CDATA_SECTION_ELEMENTS = 1339 "cdata-section-elements"; 1340 public static final String DOCTYPE_PUBLIC = "doctype-public"; 1341 public static final String DOCTYPE_SYSTEM = "doctype-system"; 1342 public static final String ENCODING = "encoding"; 1343 public static final String INDENT = "indent"; public static final String MEDIA_TYPE = "media-type"; public static final String METHOD = "method"; public static final String OMIT_XML_DECLARATION = "omit-xml-declaration"; 1347 public static final String STANDALONE = "standalone"; public static final String VERSION = "version"; 1349 1350 1351 1352 1356 private Hashtable prefixTable; 1357 private Hashtable forcedDeclTable; 1358 private Hashtable doneDeclTable; 1359 private int elementLevel = 0; 1360 private Writer output; 1361 private NamespaceSupport nsSupport; 1362 private int prefixCounter = 0; 1363 private Properties outputProperties; 1364 private boolean unicodeMode = false; 1365 private String outputEncoding = ""; 1366 private boolean htmlMode = false; 1367 private boolean cdataElement = false; 1368 1369} 1370 1371 | Popular Tags |