1 28 29 package com.caucho.vfs; 30 31 import java.io.PrintWriter ; 32 import java.io.Writer ; 33 import java.util.HashMap ; 34 35 public class XmlWriter 43 extends PrintWriter 44 { 45 public final static Strategy XML = new Xml(); 46 public final static Strategy XHTML = new Xhtml(); 47 public final static Strategy HTML = new Html(); 48 49 private boolean _isIndenting = false; 50 private int _indent = 0; 51 52 private boolean _isElementOpen; 53 private boolean _isElementOpenNeedsNewline; 54 private String _openElementName; 55 56 private Strategy _strategy = XML; 57 private String _contentType = "text/xml"; 58 private String _characterEncoding; 59 private boolean _isNewLine = true; 60 61 public XmlWriter(Writer out) 62 { 63 super(out); 64 } 65 66 public String getContentType() 67 { 68 return _contentType; 69 } 70 71 74 public void setContentType(String contentType) 75 { 76 _contentType = contentType; 77 78 if (_contentType.equals("text/xml")) 79 _strategy = XML; 80 if (_contentType.equals("application/xml")) 81 _strategy = XML; 82 else if (_contentType.equals("text/xhtml")) 83 _strategy = XHTML; 84 else if (_contentType.equals("application/xhtml+xml")) 85 _strategy = XHTML; 86 else if (_contentType.equals("text/html")) 87 _strategy = HTML; 88 else 89 _strategy = XML; 90 } 91 92 public void setStrategy(Strategy strategy) 93 { 94 _strategy = strategy; 95 } 96 97 public void setIndenting(boolean isIndenting) 98 { 99 _isIndenting = isIndenting; 100 } 101 102 public boolean isIndenting() 103 { 104 return _isIndenting; 105 } 106 107 110 public void setCharacterEncoding(String characterEncoding) 111 { 112 _characterEncoding = characterEncoding; 113 } 114 115 public String getCharacterEncoding() 116 { 117 return _characterEncoding; 118 } 119 120 private boolean closeElementIfNeeded(boolean isEnd) 121 { 122 if (_isElementOpen) { 123 _isElementOpen = false; 124 125 _strategy.closeElement(this, _openElementName, isEnd); 126 127 if (_isElementOpenNeedsNewline) { 128 _isElementOpenNeedsNewline = false; 129 softPrintln(); 130 } 131 132 return true; 133 } 134 135 return false; 136 } 137 138 private void startElement(String name, boolean isLineBefore, boolean isLineAfter) 139 { 140 closeElementIfNeeded(false); 141 142 if (isLineBefore) 143 softPrintln(); 144 145 _openElementName = name; 146 147 _strategy.openElement(this, name); 148 _isElementOpen = true; 149 _isElementOpenNeedsNewline = isLineAfter; 150 151 if (_isIndenting) 152 _indent++; 153 } 154 155 private void endElement(String name, boolean isLineBefore, boolean isLineAfter) 156 { 157 if (_isIndenting) 158 _indent--; 159 160 if (!closeElementIfNeeded(true)) { 161 if (isLineBefore) 162 softPrintln(); 163 164 _strategy.endElement(this, name); 165 } 166 167 if (isLineAfter) 168 softPrintln(); 169 } 170 171 174 public void startElement(String name) 175 { 176 startElement(name, false, false); 177 } 178 179 182 public void endElement(String name) 183 { 184 endElement(name, false, false); 185 } 186 190 public void startBlockElement(String name) 191 { 192 startElement(name, true, true); 193 } 194 195 199 public void endBlockElement(String name) 200 { 201 endElement(name, true, true); 202 } 203 204 208 public void startLineElement(String name) 209 { 210 startElement(name, true, false); 211 } 212 213 217 public void endLineElement(String name) 218 { 219 endElement(name, false, true); 220 } 221 222 226 public void writeElement(String name) 227 { 228 startElement(name); 229 endElement(name); 230 } 231 232 236 public void writeLineElement(String name) 237 { 238 startLineElement(name); 239 endLineElement(name); 240 } 241 242 246 public void writeBlockElement(String name) 247 { 248 startBlockElement(name); 249 endBlockElement(name); 250 } 251 252 256 public void writeElement(String name, Object text) 257 { 258 startElement(name); 259 writeText(text); 260 endElement(name); 261 } 262 263 267 public void writeLineElement(String name, Object text) 268 { 269 startLineElement(name); 270 writeText(text); 271 endLineElement(name); 272 } 273 274 278 public void writeBlockElement(String name, Object text) 279 { 280 startBlockElement(name); 281 writeText(text); 282 endBlockElement(name); 283 } 284 285 290 public void writeAttribute(String name, Object value) 291 { 292 if (!_isElementOpen) 293 throw new IllegalStateException ("no open element"); 294 295 if (value == null) 296 return; 297 298 _isElementOpen = false; 299 try { 300 _strategy.writeAttribute(this, name, value); 301 } 302 finally { 303 _isElementOpen = true; 304 } 305 306 } 307 308 314 public void writeAttribute(String name, Object ... values) 315 { 316 if (!_isElementOpen) 317 throw new IllegalStateException ("no open element"); 318 319 _isElementOpen = false; 320 321 try { 322 _strategy.writeAttribute(this, name, values); 323 } 324 finally { 325 _isElementOpen = true; 326 } 327 328 } 329 330 333 public void writeText(char ch) 334 { 335 closeElementIfNeeded(false); 336 writeIndentIfNewLine(); 337 _strategy.writeText(this, ch); 338 } 339 340 343 public void writeText(char[] buf) 344 { 345 closeElementIfNeeded(false); 346 writeIndentIfNewLine(); 347 348 _strategy.writeText(this, buf); 349 } 350 351 354 public void writeText(char[] buf, int offset, int length) 355 { 356 closeElementIfNeeded(false); 357 writeIndentIfNewLine(); 358 _strategy.writeText(this, buf, offset, length); 359 } 360 361 365 public void writeText(Object obj) 366 { 367 closeElementIfNeeded(false); 368 writeIndentIfNewLine(); 369 _strategy.writeTextObject(this, obj); 370 } 371 372 375 public void writeComment(String comment) 376 { 377 closeElementIfNeeded(false); 378 writeIndentIfNewLine(); 379 380 _strategy.writeComment(this, comment); 381 } 382 383 387 public void flush() 388 { 389 closeElementIfNeeded(true); 390 super.flush(); 391 } 392 393 public void println() 394 { 395 closeElementIfNeeded(false); 396 super.println(); 397 _isNewLine = true; 398 } 399 400 public boolean isNewLine() 401 { 402 return _isNewLine; 403 } 404 405 public boolean softPrintln() 406 { 407 if (!isNewLine()) { 408 println(); 409 return true; 410 } 411 else 412 return false; 413 } 414 415 public void write(int ch) 416 { 417 closeElementIfNeeded(false); 418 _isNewLine = false; 419 super.write(ch); 420 } 421 422 public void write(char buf[], int off, int len) 423 { 424 closeElementIfNeeded(false); 425 _isNewLine = false; 426 super.write(buf, off, len); 427 } 428 429 public void write(char buf[]) 430 { 431 closeElementIfNeeded(false); 432 _isNewLine = false; 433 super.write(buf); 434 } 435 436 public void write(String s, int off, int len) 437 { 438 closeElementIfNeeded(false); 439 _isNewLine = false; 440 super.write(s, off, len); 441 } 442 443 public void write(String s) 444 { 445 closeElementIfNeeded(false); 446 _isNewLine = false; 447 super.write(s); 448 } 449 450 static public abstract class Strategy 451 { 452 abstract void openElement(XmlWriter writer, String name); 453 abstract void closeElement(XmlWriter writer, String name, boolean isEnd); 454 abstract void endElement(XmlWriter writer, String name); 455 456 abstract void writeAttribute(XmlWriter writer, String name, Object value); 457 abstract void writeAttribute(XmlWriter writer, String name, Object ... values); 458 459 abstract void writeText(XmlWriter writer, char ch); 460 abstract void writeText(XmlWriter writer, char[] buf); 461 abstract void writeText(XmlWriter writer, char[] buf, int offset, int length); 462 abstract void writeTextObject(XmlWriter writer, Object obj); 463 abstract void writeComment(XmlWriter writer, String comment); 464 } 465 466 static public class Xml 467 extends Strategy 468 { 469 void openElement(XmlWriter writer, String name) 470 { 471 writer.writeIndentIfNewLine(); 472 writer.write('<'); 473 writer.write(name); 474 } 475 476 void closeElement(XmlWriter writer, String name, boolean isEnd) 477 { 478 if (isEnd) 479 writer.write('/'); 480 481 writer.write('>'); 482 } 483 484 void endElement(XmlWriter writer, String name) 485 { 486 writer.writeIndentIfNewLine(); 487 488 writer.write("</"); 489 writer.write(name); 490 writer.write('>'); 491 } 492 493 void writeAttribute(XmlWriter writer, String name, Object value) 494 { 495 writer.write(" "); 496 writer.write(name); 497 writer.write('='); 498 writer.write("'"); 499 writeAttributeValue(writer, name, value); 500 writer.write("'"); 501 } 502 503 void writeAttribute(XmlWriter writer, String name, Object ... values) 504 { 505 writer.write(" "); 506 writer.write(name); 507 writer.write('='); 508 writer.write("'"); 509 510 int len = values.length; 511 512 for (int i = 0; i < len; i++) { 513 Object value = values[i]; 514 515 if (value == null) 516 continue; 517 518 if (i > 0) 519 writer.write(' '); 520 521 writeAttributeValue(writer, name, value); 522 } 523 524 writer.write("'"); 525 } 526 527 protected void writeAttributeValue(XmlWriter writer, String name, Object value) 528 { 529 writeXmlEscaped(writer, value); 530 } 531 532 public void writeText(XmlWriter writer, char ch) 533 { 534 writeXmlEscapedChar(writer, ch); 535 } 536 537 public void writeText(XmlWriter writer, char[] buf) 538 { 539 int endIndex = buf.length; 540 541 for (int i = 0; i < endIndex; i++) { 542 writeXmlEscapedChar(writer, buf[i]); 543 } 544 } 545 546 public void writeText(XmlWriter writer, char[] buf, int offset, int length) 547 { 548 int endIndex = offset + length; 549 550 for (int i = offset; i < endIndex; i++) { 551 writeXmlEscapedChar(writer, buf[i]); 552 } 553 } 554 555 public void writeTextObject(XmlWriter writer, Object obj) 556 { 557 String string = String.valueOf(obj); 558 int len = string.length(); 559 560 for (int i = 0; i < len; i++) { 561 writeXmlEscapedChar(writer, string.charAt(i)); 562 } 563 } 564 565 public void writeComment(XmlWriter writer, String comment) 566 { 567 writer.write("<!-- "); 568 writeXmlEscaped(writer, comment); 569 writer.write(" -->"); 570 } 571 572 private void writeXmlEscapedChar(XmlWriter writer, char ch) 573 { 574 switch (ch) { 575 case '<': 576 writer.write("<"); break; 577 case '>': 578 writer.write(">"); break; 579 case '&': 580 writer.write("&"); break; 581 case '\"': 582 writer.write("""); break; 583 case '\'': 584 writer.write("'"); break; 585 default: 586 writer.write(ch); 587 } 588 } 589 590 private void writeXmlEscaped(XmlWriter writer, Object object) 591 { 592 String string = object.toString(); 593 594 int len = string.length(); 595 596 for (int i = 0; i < len; i++) { 597 writeXmlEscapedChar(writer, string.charAt(i)); 598 } 599 } 600 601 } 602 603 private void writeIndentIfNewLine() 604 { 605 if (isNewLine()) { 606 for (int i = _indent * 2; i > 0; i--) { 607 write(' '); 608 } 609 } 610 } 611 612 615 static public class Xhtml 616 extends Xml 617 { 618 private int EMPTY = 1; 619 private int BREAK_BEFORE = 2; 620 private int BREAK_AFTER = 4; 621 private int BREAK_AFTER_CONTENT = 8; 622 private int EAT_BREAK_BEFORE = 16; private int BOOLEAN_ATTRIBUTE = 1024; 624 625 private HashMap <String , Integer > _flags = new HashMap <String , Integer >(); 626 627 public Xhtml() 628 { 629 addFlags("html", BREAK_BEFORE | BREAK_AFTER); 630 addFlags("head", BREAK_BEFORE | BREAK_AFTER); 631 addFlags("body", BREAK_BEFORE | BREAK_AFTER); 632 633 addFlags("style", BREAK_BEFORE | BREAK_AFTER); 634 addFlags("meta", BREAK_BEFORE | BREAK_AFTER | EMPTY); 635 addFlags("link", BREAK_BEFORE | BREAK_AFTER | EMPTY); 636 addFlags("title", BREAK_BEFORE | BREAK_AFTER_CONTENT); 637 addFlags("base", BREAK_BEFORE | BREAK_AFTER | EMPTY); 638 639 640 addFlags("h1", BREAK_BEFORE | BREAK_AFTER_CONTENT); 641 addFlags("h2", BREAK_BEFORE | BREAK_AFTER_CONTENT); 642 addFlags("h3", BREAK_BEFORE | BREAK_AFTER_CONTENT); 643 addFlags("h4", BREAK_BEFORE | BREAK_AFTER_CONTENT); 644 addFlags("h5", BREAK_BEFORE | BREAK_AFTER_CONTENT); 645 addFlags("h6", BREAK_BEFORE | BREAK_AFTER_CONTENT); 646 647 addFlags("p", BREAK_BEFORE | BREAK_AFTER); 648 addFlags("div", BREAK_BEFORE | BREAK_AFTER); 649 650 addFlags("ul", BREAK_BEFORE | BREAK_AFTER); 651 addFlags("ol", BREAK_BEFORE | BREAK_AFTER); 652 653 addFlags("li", BREAK_BEFORE | BREAK_AFTER_CONTENT); 654 655 addFlags("dl", BREAK_BEFORE | BREAK_AFTER); 656 addFlags("dt", BREAK_BEFORE | BREAK_AFTER_CONTENT); 657 addFlags("dd", BREAK_BEFORE | BREAK_AFTER_CONTENT); 658 659 addFlags("hr", BREAK_BEFORE | BREAK_AFTER | EMPTY); 660 addFlags("br", BREAK_AFTER | EMPTY); 661 addFlags("option", EMPTY); 662 663 addFlags("img", EMPTY); 664 665 addFlags("area", EMPTY); 666 667 addFlags("pre", BREAK_BEFORE | BREAK_AFTER); 668 669 addFlags("blockquote", BREAK_BEFORE | BREAK_AFTER); 670 addFlags("address", BREAK_BEFORE | BREAK_AFTER); 671 672 addFlags("fieldset", BREAK_BEFORE | BREAK_AFTER); 673 addFlags("form", BREAK_BEFORE | BREAK_AFTER); 674 addFlags("ins", BREAK_BEFORE | BREAK_AFTER); 675 addFlags("del", BREAK_BEFORE | BREAK_AFTER); 676 addFlags("script", BREAK_BEFORE | BREAK_AFTER); 677 addFlags("noscript", BREAK_BEFORE | BREAK_AFTER); 678 679 addFlags("input", EMPTY); 680 681 688 addFlags("table", BREAK_BEFORE | BREAK_AFTER); 689 addFlags("thead", BREAK_BEFORE | BREAK_AFTER); 690 addFlags("tfoot", BREAK_BEFORE | BREAK_AFTER); 691 addFlags("tr", BREAK_BEFORE | BREAK_AFTER_CONTENT); 692 addFlags("col", EMPTY); 693 694 addFlags("object", BREAK_BEFORE | BREAK_AFTER); 695 addFlags("param", BREAK_BEFORE | BREAK_AFTER | EMPTY); 696 697 addFlags("compact", BOOLEAN_ATTRIBUTE); 698 addFlags("nowrap", BOOLEAN_ATTRIBUTE); 699 addFlags("ismap", BOOLEAN_ATTRIBUTE); 700 addFlags("declare", BOOLEAN_ATTRIBUTE); 701 addFlags("noshade", BOOLEAN_ATTRIBUTE); 702 addFlags("checked", BOOLEAN_ATTRIBUTE); 703 addFlags("disabled", BOOLEAN_ATTRIBUTE); 704 addFlags("readonly", BOOLEAN_ATTRIBUTE); 705 addFlags("multiple", BOOLEAN_ATTRIBUTE); 706 addFlags("selected", BOOLEAN_ATTRIBUTE); 707 addFlags("noresize", BOOLEAN_ATTRIBUTE); 708 addFlags("defer", BOOLEAN_ATTRIBUTE); 709 } 710 711 protected void addFlags(String name, int flag) 712 { 713 int intValue = getFlags(name); 714 715 intValue |= flag; 716 717 _flags.put(name, intValue); 718 } 719 720 protected int getFlags(String name) 721 { 722 int intValue; 723 724 Integer integer = _flags.get(name); 725 726 if (integer == null) 727 intValue = 0; 728 else 729 intValue = integer; 730 731 return intValue; 732 } 733 734 void openElement(XmlWriter writer, String name) 735 { 736 int flags = getFlags(name); 737 738 if ((flags & BREAK_BEFORE) > 0) 739 writer.softPrintln(); 740 741 writer.writeIndentIfNewLine(); 742 743 writer.write('<'); 744 writer.write(name); 745 } 746 747 protected void writeAttributeValue(XmlWriter writer, String name, Object value) 748 { 749 int flags = getFlags(name); 750 751 if ( (flags & BOOLEAN_ATTRIBUTE) > 0) 752 value = name.toUpperCase(); 753 754 super.writeAttributeValue(writer, name, value); 755 } 756 757 void closeElement(XmlWriter writer, String name, boolean isEnd) 758 { 759 int flags = getFlags(name); 760 761 boolean isEmpty = (flags & EMPTY) > 0; 762 763 if (isEnd && isEmpty) 764 writer.write(" />"); 765 else 766 writer.write('>'); 767 768 if ((flags & BREAK_AFTER) > 0) 769 writer.softPrintln(); 770 771 if (isEnd && !isEmpty) 772 endElement(writer, name); 773 } 774 775 void endElement(XmlWriter writer, String name) 776 { 777 int flags = getFlags(name); 778 779 boolean isFullBreak = (flags & (BREAK_BEFORE | BREAK_AFTER)) == (BREAK_BEFORE | BREAK_AFTER); 780 781 if (isFullBreak) 782 writer.softPrintln(); 783 784 writer.writeIndentIfNewLine(); 785 786 if ((flags & EMPTY) == 0) { 787 writer.write("</"); 788 writer.write(name); 789 writer.write('>'); 790 } 791 792 if (isFullBreak || ( (flags & BREAK_AFTER_CONTENT) > 0)) 793 writer.softPrintln(); 794 } 795 796 protected void writeDoctype(XmlWriter writer) 797 { 798 800 writer.println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">"); 801 802 815 } 816 817 protected void writeXmlDeclaration(XmlWriter writer) 818 { 819 String encoding = writer.getCharacterEncoding(); 820 821 writer.println("<?xml version=\"1.0\" encoding=\"" + encoding + "\"?>"); 822 } 823 824 } 825 826 static public class Html 827 extends Xhtml 828 { 829 public Html() 830 { 831 } 832 } 833 } 834 | Popular Tags |