1 16 17 package dom; 18 19 import java.io.OutputStream ; 20 import java.io.OutputStreamWriter ; 21 import java.io.PrintWriter ; 22 import java.io.UnsupportedEncodingException ; 23 import java.lang.reflect.Method ; 24 25 import org.w3c.dom.Attr ; 26 import org.w3c.dom.Document ; 27 import org.w3c.dom.DocumentType ; 28 import org.w3c.dom.NamedNodeMap ; 29 import org.w3c.dom.Node ; 30 import org.xml.sax.SAXException ; 31 import org.xml.sax.SAXParseException ; 32 33 41 public class Writer { 42 43 47 49 50 protected static final String NAMESPACES_FEATURE_ID = "http://xml.org/sax/features/namespaces"; 51 52 53 protected static final String VALIDATION_FEATURE_ID = "http://xml.org/sax/features/validation"; 54 55 56 protected static final String SCHEMA_VALIDATION_FEATURE_ID = "http://apache.org/xml/features/validation/schema"; 57 58 59 protected static final String SCHEMA_FULL_CHECKING_FEATURE_ID = "http://apache.org/xml/features/validation/schema-full-checking"; 60 61 62 protected static final String VALIDATE_ANNOTATIONS_ID = "http://apache.org/xml/features/validate-annotations"; 63 64 65 protected static final String GENERATE_SYNTHETIC_ANNOTATIONS_ID = "http://apache.org/xml/features/generate-synthetic-annotations"; 66 67 68 protected static final String DYNAMIC_VALIDATION_FEATURE_ID = "http://apache.org/xml/features/validation/dynamic"; 69 70 71 protected static final String LOAD_EXTERNAL_DTD_FEATURE_ID = "http://apache.org/xml/features/nonvalidating/load-external-dtd"; 72 73 74 protected static final String XINCLUDE_FEATURE_ID = "http://apache.org/xml/features/xinclude"; 75 76 77 protected static final String XINCLUDE_FIXUP_BASE_URIS_FEATURE_ID = "http://apache.org/xml/features/xinclude/fixup-base-uris"; 78 79 80 protected static final String XINCLUDE_FIXUP_LANGUAGE_FEATURE_ID = "http://apache.org/xml/features/xinclude/fixup-language"; 81 82 84 85 protected static final String DEFAULT_PARSER_NAME = "dom.wrappers.Xerces"; 86 87 88 protected static final boolean DEFAULT_NAMESPACES = true; 89 90 91 protected static final boolean DEFAULT_VALIDATION = false; 92 93 94 protected static final boolean DEFAULT_LOAD_EXTERNAL_DTD = true; 95 96 97 protected static final boolean DEFAULT_SCHEMA_VALIDATION = false; 98 99 100 protected static final boolean DEFAULT_SCHEMA_FULL_CHECKING = false; 101 102 103 protected static final boolean DEFAULT_VALIDATE_ANNOTATIONS = false; 104 105 106 protected static final boolean DEFAULT_GENERATE_SYNTHETIC_ANNOTATIONS = false; 107 108 109 protected static final boolean DEFAULT_DYNAMIC_VALIDATION = false; 110 111 112 protected static final boolean DEFAULT_XINCLUDE = false; 113 114 115 protected static final boolean DEFAULT_XINCLUDE_FIXUP_BASE_URIS = true; 116 117 118 protected static final boolean DEFAULT_XINCLUDE_FIXUP_LANGUAGE = true; 119 120 121 protected static final boolean DEFAULT_CANONICAL = false; 122 123 127 128 protected PrintWriter fOut; 129 130 131 protected boolean fCanonical; 132 133 134 protected boolean fXML11; 135 136 140 141 public Writer() { 142 } 144 public Writer(boolean canonical) { 145 fCanonical = canonical; 146 } 148 152 153 public void setCanonical(boolean canonical) { 154 fCanonical = canonical; 155 } 157 158 public void setOutput(OutputStream stream, String encoding) 159 throws UnsupportedEncodingException { 160 161 if (encoding == null) { 162 encoding = "UTF8"; 163 } 164 165 java.io.Writer writer = new OutputStreamWriter (stream, encoding); 166 fOut = new PrintWriter (writer); 167 168 } 170 171 public void setOutput(java.io.Writer writer) { 172 173 fOut = writer instanceof PrintWriter 174 ? (PrintWriter )writer : new PrintWriter (writer); 175 176 } 178 179 public void write(Node node) { 180 181 if (node == null) { 183 return; 184 } 185 186 short type = node.getNodeType(); 187 switch (type) { 188 case Node.DOCUMENT_NODE: { 189 Document document = (Document )node; 190 fXML11 = "1.1".equals(getVersion(document)); 191 if (!fCanonical) { 192 if (fXML11) { 193 fOut.println("<?xml version=\"1.1\" encoding=\"UTF-8\"?>"); 194 } 195 else { 196 fOut.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); 197 } 198 fOut.flush(); 199 write(document.getDoctype()); 200 } 201 write(document.getDocumentElement()); 202 break; 203 } 204 205 case Node.DOCUMENT_TYPE_NODE: { 206 DocumentType doctype = (DocumentType )node; 207 fOut.print("<!DOCTYPE "); 208 fOut.print(doctype.getName()); 209 String publicId = doctype.getPublicId(); 210 String systemId = doctype.getSystemId(); 211 if (publicId != null) { 212 fOut.print(" PUBLIC '"); 213 fOut.print(publicId); 214 fOut.print("' '"); 215 fOut.print(systemId); 216 fOut.print('\''); 217 } 218 else if (systemId != null) { 219 fOut.print(" SYSTEM '"); 220 fOut.print(systemId); 221 fOut.print('\''); 222 } 223 String internalSubset = doctype.getInternalSubset(); 224 if (internalSubset != null) { 225 fOut.println(" ["); 226 fOut.print(internalSubset); 227 fOut.print(']'); 228 } 229 fOut.println('>'); 230 break; 231 } 232 233 case Node.ELEMENT_NODE: { 234 fOut.print('<'); 235 fOut.print(node.getNodeName()); 236 Attr attrs[] = sortAttributes(node.getAttributes()); 237 for (int i = 0; i < attrs.length; i++) { 238 Attr attr = attrs[i]; 239 fOut.print(' '); 240 fOut.print(attr.getNodeName()); 241 fOut.print("=\""); 242 normalizeAndPrint(attr.getNodeValue(), true); 243 fOut.print('"'); 244 } 245 fOut.print('>'); 246 fOut.flush(); 247 248 Node child = node.getFirstChild(); 249 while (child != null) { 250 write(child); 251 child = child.getNextSibling(); 252 } 253 break; 254 } 255 256 case Node.ENTITY_REFERENCE_NODE: { 257 if (fCanonical) { 258 Node child = node.getFirstChild(); 259 while (child != null) { 260 write(child); 261 child = child.getNextSibling(); 262 } 263 } 264 else { 265 fOut.print('&'); 266 fOut.print(node.getNodeName()); 267 fOut.print(';'); 268 fOut.flush(); 269 } 270 break; 271 } 272 273 case Node.CDATA_SECTION_NODE: { 274 if (fCanonical) { 275 normalizeAndPrint(node.getNodeValue(), false); 276 } 277 else { 278 fOut.print("<![CDATA["); 279 fOut.print(node.getNodeValue()); 280 fOut.print("]]>"); 281 } 282 fOut.flush(); 283 break; 284 } 285 286 case Node.TEXT_NODE: { 287 normalizeAndPrint(node.getNodeValue(), false); 288 fOut.flush(); 289 break; 290 } 291 292 case Node.PROCESSING_INSTRUCTION_NODE: { 293 fOut.print("<?"); 294 fOut.print(node.getNodeName()); 295 String data = node.getNodeValue(); 296 if (data != null && data.length() > 0) { 297 fOut.print(' '); 298 fOut.print(data); 299 } 300 fOut.print("?>"); 301 fOut.flush(); 302 break; 303 } 304 305 case Node.COMMENT_NODE: { 306 if (!fCanonical) { 307 fOut.print("<!--"); 308 String comment = node.getNodeValue(); 309 if (comment != null && comment.length() > 0) { 310 fOut.print(comment); 311 } 312 fOut.print("-->"); 313 fOut.flush(); 314 } 315 } 316 } 317 318 if (type == Node.ELEMENT_NODE) { 319 fOut.print("</"); 320 fOut.print(node.getNodeName()); 321 fOut.print('>'); 322 fOut.flush(); 323 } 324 325 } 327 328 protected Attr [] sortAttributes(NamedNodeMap attrs) { 329 330 int len = (attrs != null) ? attrs.getLength() : 0; 331 Attr array[] = new Attr [len]; 332 for (int i = 0; i < len; i++) { 333 array[i] = (Attr )attrs.item(i); 334 } 335 for (int i = 0; i < len - 1; i++) { 336 String name = array[i].getNodeName(); 337 int index = i; 338 for (int j = i + 1; j < len; j++) { 339 String curName = array[j].getNodeName(); 340 if (curName.compareTo(name) < 0) { 341 name = curName; 342 index = j; 343 } 344 } 345 if (index != i) { 346 Attr temp = array[i]; 347 array[i] = array[index]; 348 array[index] = temp; 349 } 350 } 351 352 return array; 353 354 } 356 360 361 protected void normalizeAndPrint(String s, boolean isAttValue) { 362 363 int len = (s != null) ? s.length() : 0; 364 for (int i = 0; i < len; i++) { 365 char c = s.charAt(i); 366 normalizeAndPrint(c, isAttValue); 367 } 368 369 } 371 372 protected void normalizeAndPrint(char c, boolean isAttValue) { 373 374 switch (c) { 375 case '<': { 376 fOut.print("<"); 377 break; 378 } 379 case '>': { 380 fOut.print(">"); 381 break; 382 } 383 case '&': { 384 fOut.print("&"); 385 break; 386 } 387 case '"': { 388 if (isAttValue) { 391 fOut.print("""); 392 } 393 else { 394 fOut.print("\""); 395 } 396 break; 397 } 398 case '\r': { 399 fOut.print("
"); 404 break; 405 } 406 case '\n': { 407 if (fCanonical) { 408 fOut.print("
"); 409 break; 410 } 411 } 413 default: { 414 if (fXML11 && ((c >= 0x01 && c <= 0x1F && c != 0x09 && c != 0x0A) 423 || (c >= 0x7F && c <= 0x9F) || c == 0x2028) 424 || isAttValue && (c == 0x09 || c == 0x0A)) { 425 fOut.print("&#x"); 426 fOut.print(Integer.toHexString(c).toUpperCase()); 427 fOut.print(";"); 428 } 429 else { 430 fOut.print(c); 431 } 432 } 433 } 434 } 436 437 protected String getVersion(Document document) { 438 if (document == null) { 439 return null; 440 } 441 String version = null; 442 Method getXMLVersion = null; 443 try { 444 getXMLVersion = document.getClass().getMethod("getXmlVersion", new Class []{}); 445 if (getXMLVersion != null) { 447 version = (String ) getXMLVersion.invoke(document, (Object []) null); 448 } 449 } 450 catch (Exception e) { 451 } 454 return version; 455 } 457 461 462 public static void main(String argv[]) { 463 464 if (argv.length == 0) { 466 printUsage(); 467 System.exit(1); 468 } 469 470 Writer writer = null; 472 ParserWrapper parser = null; 473 boolean namespaces = DEFAULT_NAMESPACES; 474 boolean validation = DEFAULT_VALIDATION; 475 boolean externalDTD = DEFAULT_LOAD_EXTERNAL_DTD; 476 boolean schemaValidation = DEFAULT_SCHEMA_VALIDATION; 477 boolean schemaFullChecking = DEFAULT_SCHEMA_FULL_CHECKING; 478 boolean validateAnnotations = DEFAULT_VALIDATE_ANNOTATIONS; 479 boolean generateSyntheticAnnotations = DEFAULT_GENERATE_SYNTHETIC_ANNOTATIONS; 480 boolean dynamicValidation = DEFAULT_DYNAMIC_VALIDATION; 481 boolean xincludeProcessing = DEFAULT_XINCLUDE; 482 boolean xincludeFixupBaseURIs = DEFAULT_XINCLUDE_FIXUP_BASE_URIS; 483 boolean xincludeFixupLanguage = DEFAULT_XINCLUDE_FIXUP_LANGUAGE; 484 boolean canonical = DEFAULT_CANONICAL; 485 486 for (int i = 0; i < argv.length; i++) { 488 String arg = argv[i]; 489 if (arg.startsWith("-")) { 490 String option = arg.substring(1); 491 if (option.equals("p")) { 492 if (++i == argv.length) { 494 System.err.println("error: Missing argument to -p option."); 495 } 496 String parserName = argv[i]; 497 498 try { 500 parser = (ParserWrapper)Class.forName(parserName).newInstance(); 501 } 502 catch (Exception e) { 503 parser = null; 504 System.err.println("error: Unable to instantiate parser ("+parserName+")"); 505 } 506 continue; 507 } 508 if (option.equalsIgnoreCase("n")) { 509 namespaces = option.equals("n"); 510 continue; 511 } 512 if (option.equalsIgnoreCase("v")) { 513 validation = option.equals("v"); 514 continue; 515 } 516 if (option.equalsIgnoreCase("xd")) { 517 externalDTD = option.equals("xd"); 518 continue; 519 } 520 if (option.equalsIgnoreCase("s")) { 521 schemaValidation = option.equals("s"); 522 continue; 523 } 524 if (option.equalsIgnoreCase("f")) { 525 schemaFullChecking = option.equals("f"); 526 continue; 527 } 528 if (option.equalsIgnoreCase("va")) { 529 validateAnnotations = option.equals("va"); 530 continue; 531 } 532 if (option.equalsIgnoreCase("ga")) { 533 generateSyntheticAnnotations = option.equals("ga"); 534 continue; 535 } 536 if (option.equalsIgnoreCase("dv")) { 537 dynamicValidation = option.equals("dv"); 538 continue; 539 } 540 if (option.equalsIgnoreCase("xi")) { 541 xincludeProcessing = option.equals("xi"); 542 continue; 543 } 544 if (option.equalsIgnoreCase("xb")) { 545 xincludeFixupBaseURIs = option.equals("xb"); 546 continue; 547 } 548 if (option.equalsIgnoreCase("xl")) { 549 xincludeFixupLanguage = option.equals("xl"); 550 continue; 551 } 552 if (option.equalsIgnoreCase("c")) { 553 canonical = option.equals("c"); 554 continue; 555 } 556 if (option.equals("h")) { 557 printUsage(); 558 continue; 559 } 560 } 561 562 if (parser == null) { 564 565 try { 567 parser = (ParserWrapper)Class.forName(DEFAULT_PARSER_NAME).newInstance(); 568 } 569 catch (Exception e) { 570 System.err.println("error: Unable to instantiate parser ("+DEFAULT_PARSER_NAME+")"); 571 continue; 572 } 573 } 574 575 try { 577 parser.setFeature(NAMESPACES_FEATURE_ID, namespaces); 578 } 579 catch (SAXException e) { 580 System.err.println("warning: Parser does not support feature ("+NAMESPACES_FEATURE_ID+")"); 581 } 582 try { 583 parser.setFeature(VALIDATION_FEATURE_ID, validation); 584 } 585 catch (SAXException e) { 586 System.err.println("warning: Parser does not support feature ("+VALIDATION_FEATURE_ID+")"); 587 } 588 try { 589 parser.setFeature(LOAD_EXTERNAL_DTD_FEATURE_ID, externalDTD); 590 } 591 catch (SAXException e) { 592 System.err.println("warning: Parser does not support feature ("+LOAD_EXTERNAL_DTD_FEATURE_ID+")"); 593 } 594 try { 595 parser.setFeature(SCHEMA_VALIDATION_FEATURE_ID, schemaValidation); 596 } 597 catch (SAXException e) { 598 System.err.println("warning: Parser does not support feature ("+SCHEMA_VALIDATION_FEATURE_ID+")"); 599 } 600 try { 601 parser.setFeature(SCHEMA_FULL_CHECKING_FEATURE_ID, schemaFullChecking); 602 } 603 catch (SAXException e) { 604 System.err.println("warning: Parser does not support feature ("+SCHEMA_FULL_CHECKING_FEATURE_ID+")"); 605 } 606 try { 607 parser.setFeature(VALIDATE_ANNOTATIONS_ID, validateAnnotations); 608 } 609 catch (SAXException e) { 610 System.err.println("warning: Parser does not support feature ("+VALIDATE_ANNOTATIONS_ID+")"); 611 } 612 try { 613 parser.setFeature(GENERATE_SYNTHETIC_ANNOTATIONS_ID, generateSyntheticAnnotations); 614 } 615 catch (SAXException e) { 616 System.err.println("warning: Parser does not support feature ("+GENERATE_SYNTHETIC_ANNOTATIONS_ID+")"); 617 } 618 try { 619 parser.setFeature(DYNAMIC_VALIDATION_FEATURE_ID, dynamicValidation); 620 } 621 catch (SAXException e) { 622 System.err.println("warning: Parser does not support feature ("+DYNAMIC_VALIDATION_FEATURE_ID+")"); 623 } 624 try { 625 parser.setFeature(XINCLUDE_FEATURE_ID, xincludeProcessing); 626 } 627 catch (SAXException e) { 628 System.err.println("warning: Parser does not support feature ("+XINCLUDE_FEATURE_ID+")"); 629 } 630 try { 631 parser.setFeature(XINCLUDE_FIXUP_BASE_URIS_FEATURE_ID, xincludeFixupBaseURIs); 632 } 633 catch (SAXException e) { 634 System.err.println("warning: Parser does not support feature ("+XINCLUDE_FIXUP_BASE_URIS_FEATURE_ID+")"); 635 } 636 try { 637 parser.setFeature(XINCLUDE_FIXUP_LANGUAGE_FEATURE_ID, xincludeFixupLanguage); 638 } 639 catch (SAXException e) { 640 System.err.println("warning: Parser does not support feature ("+XINCLUDE_FIXUP_LANGUAGE_FEATURE_ID+")"); 641 } 642 643 if (writer == null) { 645 writer = new Writer(); 646 try { 647 writer.setOutput(System.out, "UTF8"); 648 } 649 catch (UnsupportedEncodingException e) { 650 System.err.println("error: Unable to set output. Exiting."); 651 System.exit(1); 652 } 653 } 654 655 writer.setCanonical(canonical); 657 try { 658 Document document = parser.parse(arg); 659 writer.write(document); 660 } 661 catch (SAXParseException e) { 662 } 664 catch (Exception e) { 665 System.err.println("error: Parse error occurred - "+e.getMessage()); 666 if (e instanceof SAXException ) { 667 Exception nested = ((SAXException )e).getException(); 668 if (nested != null) { 669 e = nested; 670 } 671 } 672 e.printStackTrace(System.err); 673 } 674 } 675 676 } 678 682 683 private static void printUsage() { 684 685 System.err.println("usage: java dom.Writer (options) uri ..."); 686 System.err.println(); 687 688 System.err.println("options:"); 689 System.err.println(" -p name Select parser by name."); 690 System.err.println(" -n | -N Turn on/off namespace processing."); 691 System.err.println(" -v | -V Turn on/off validation."); 692 System.err.println(" -xd | -XD Turn on/off loading of external DTDs."); 693 System.err.println(" NOTE: Always on when -v in use and not supported by all parsers."); 694 System.err.println(" -s | -S Turn on/off Schema validation support."); 695 System.err.println(" NOTE: Not supported by all parsers."); 696 System.err.println(" -f | -F Turn on/off Schema full checking."); 697 System.err.println(" NOTE: Requires use of -s and not supported by all parsers."); 698 System.err.println(" -va | -VA Turn on/off validation of schema annotations."); 699 System.err.println(" NOTE: Requires use of -s and not supported by all parsers."); 700 System.err.println(" -ga | -GA Turn on/off generation of synthetic schema annotations."); 701 System.err.println(" NOTE: Requires use of -s and not supported by all parsers."); 702 System.err.println(" -dv | -DV Turn on/off dynamic validation."); 703 System.err.println(" NOTE: Not supported by all parsers."); 704 System.err.println(" -xi | -XI Turn on/off XInclude processing."); 705 System.err.println(" NOTE: Not supported by all parsers."); 706 System.err.println(" -xb | -XB Turn on/off base URI fixup during XInclude processing."); 707 System.err.println(" NOTE: Requires use of -xi and not supported by all parsers."); 708 System.err.println(" -xl | -XL Turn on/off language fixup during XInclude processing."); 709 System.err.println(" NOTE: Requires use of -xi and not supported by all parsers."); 710 System.err.println(" -c | -C Turn on/off Canonical XML output."); 711 System.err.println(" NOTE: This is not W3C canonical output."); 712 System.err.println(" -h This help screen."); 713 System.err.println(); 714 715 System.err.println("defaults:"); 716 System.err.println(" Parser: "+DEFAULT_PARSER_NAME); 717 System.err.print(" Namespaces: "); 718 System.err.println(DEFAULT_NAMESPACES ? "on" : "off"); 719 System.err.print(" Validation: "); 720 System.err.println(DEFAULT_VALIDATION ? "on" : "off"); 721 System.err.print(" Load External DTD: "); 722 System.err.println(DEFAULT_LOAD_EXTERNAL_DTD ? "on" : "off"); 723 System.err.print(" Schema: "); 724 System.err.println(DEFAULT_SCHEMA_VALIDATION ? "on" : "off"); 725 System.err.print(" Schema full checking: "); 726 System.err.println(DEFAULT_SCHEMA_FULL_CHECKING ? "on" : "off"); 727 System.err.print(" Dynamic: "); 728 System.err.println(DEFAULT_DYNAMIC_VALIDATION ? "on" : "off"); 729 System.err.print(" Canonical: "); 730 System.err.println(DEFAULT_CANONICAL ? "on" : "off"); 731 System.err.print(" Validate Annotations: "); 732 System.err.println(DEFAULT_VALIDATE_ANNOTATIONS ? "on" : "off"); 733 System.err.print(" Generate Synthetic Annotations: "); 734 System.err.println(DEFAULT_GENERATE_SYNTHETIC_ANNOTATIONS ? "on" : "off"); 735 System.err.print(" XInclude: "); 736 System.err.println(DEFAULT_XINCLUDE ? "on" : "off"); 737 System.err.print(" XInclude base URI fixup: "); 738 System.err.println(DEFAULT_XINCLUDE_FIXUP_BASE_URIS ? "on" : "off"); 739 System.err.print(" XInclude language fixup: "); 740 System.err.println(DEFAULT_XINCLUDE_FIXUP_LANGUAGE ? "on" : "off"); 741 742 } 744 } | Popular Tags |