1 28 29 package com.caucho.xml; 30 31 import com.caucho.java.LineMap; 32 import com.caucho.log.Log; 33 import com.caucho.util.CharBuffer; 34 import com.caucho.util.IntMap; 35 import com.caucho.util.L10N; 36 import com.caucho.vfs.EnclosedWriteStream; 37 import com.caucho.vfs.Path; 38 import com.caucho.vfs.Vfs; 39 import com.caucho.vfs.WriteStream; 40 41 import org.w3c.dom.*; 42 import org.xml.sax.Locator ; 43 44 import java.io.IOException ; 45 import java.io.OutputStream ; 46 import java.io.UnsupportedEncodingException ; 47 import java.io.Writer ; 48 import java.util.ArrayList ; 49 import java.util.HashMap ; 50 import java.util.logging.Logger ; 51 52 65 public class XmlPrinter implements XMLWriter { 66 static final Logger log = Log.open(XmlPrinter.class); 67 static final L10N L = new L10N(XmlPrinter.class); 68 69 private static final int NO_PRETTY = 0; 70 private static final int INLINE = 1; 71 private static final int NO_INDENT = 2; 72 private static final int PRE = 3; 73 74 private static final char OMITTED_SPACE = 0; 75 private static final char OMITTED_NEWLINE = 1; 76 private static final char OMITTED = 2; 77 private static final char NULL_SPACE = 3; 78 private static final char SPACE = 4; 79 private static final char NEWLINE = 5; 80 private static final char WHITESPACE = 6; 81 82 private static final int ALWAYS_EMPTY = 1; 83 private static final int EMPTY_IF_EMPTY = 2; 84 85 private static IntMap _empties; 86 private static HashMap <String ,String > _booleanAttrs; 87 private static HashMap <String ,String > _verbatimTags; 88 private static IntMap _prettyMap; 89 90 private WriteStream _os; 91 private char []_buffer = new char[256]; 92 private int _capacity = _buffer.length; 93 private int _length; 94 95 boolean _isAutomaticMethod = true; 96 boolean _isTop = true; 97 boolean _isJsp = false; 98 String _encoding; 99 String _method; 100 boolean _isText; 101 boolean _isHtml; 102 boolean _inHead; 103 String _version; 104 105 boolean _isAutomaticPretty = true; 106 boolean _isPretty; 107 int _indent; 108 int _preCount; 109 int _lastTextChar = NULL_SPACE; 110 boolean _hasMetaContentType = false; 111 boolean _includeContentType = true; 112 113 boolean _printDeclaration; 114 115 String _standalone; 116 String _systemId; 117 String _publicId; 118 private ExtendedLocator _locator; 119 120 boolean _escapeText = true; 121 boolean _inVerbatim = false; 122 123 private HashMap <String ,String > _namespace; 124 private HashMap <String ,String > _cdataElements; 125 private Entities _entities; 126 private String _mimeType; 127 128 private ArrayList <String > _prefixList; 129 130 private ArrayList <String > _attributeNames = new ArrayList <String >(); 131 private ArrayList <String > _attributeValues = new ArrayList <String >(); 132 133 private char []_cbuf = new char[256]; 134 private char []_abuf = new char[256]; 135 136 private LineMap _lineMap; 137 private int _line; 138 private String _srcFilename; 139 private int _srcLine; 140 141 private String _currentElement; 142 private Document _currentDocument; 143 144 private boolean _isEnclosedStream; 145 146 150 public XmlPrinter() 151 { 152 } 153 154 159 public XmlPrinter(OutputStream os) 160 { 161 if (os instanceof WriteStream) 162 init((WriteStream) os); 163 else if (os instanceof EnclosedWriteStream) 164 init(((EnclosedWriteStream) os).getWriteStream()); 165 else { 166 _isEnclosedStream = true; 167 WriteStream ws = Vfs.openWrite(os); 168 try { 169 ws.setEncoding("UTF-8"); 170 } catch (UnsupportedEncodingException e) { 171 } 172 init(ws); 173 } 174 } 175 176 181 public XmlPrinter(Writer writer) 182 { 183 if (writer instanceof EnclosedWriteStream) 184 init(((EnclosedWriteStream) writer).getWriteStream()); 185 else { 186 _isEnclosedStream = true; 187 WriteStream ws = Vfs.openWrite(writer); 188 init(ws); 189 } 190 } 191 192 197 public void init(WriteStream os) 198 { 199 _os = os; 200 init(); 201 } 202 203 206 void init() 207 { 208 String encoding = null; 209 210 if (_os != null) 211 encoding = _os.getEncoding(); 212 213 _length = 0; 214 215 if (encoding == null || 216 encoding.equals("US-ASCII") || encoding.equals("ISO-8859-1")) 217 _entities = XmlLatin1Entities.create(); 218 else 219 _entities = XmlEntities.create(); 220 _encoding = encoding; 221 _namespace = new HashMap <String ,String >(); 222 _line = 1; 223 _isTop = true; 224 _hasMetaContentType = false; 225 _attributeNames.clear(); 226 _attributeValues.clear(); 227 } 228 229 235 public static void print(Path path, Node node) 236 throws IOException 237 { 238 WriteStream os = path.openWrite(); 239 240 try { 241 new XmlPrinter(os).printXml(node); 242 } finally { 243 os.close(); 244 } 245 } 246 247 253 public void printXml(Node node) 254 throws IOException 255 { 256 _isAutomaticMethod = false; 257 258 ((QAbstractNode) node).print(this); 259 260 flush(); 261 } 262 263 268 public void printHtml(Node node) 269 throws IOException 270 { 271 setMethod("html"); 272 setVersion("4.0"); 273 274 ((QAbstractNode) node).print(this); 275 276 flush(); 277 } 278 279 284 public void printPrettyXml(Node node) 285 throws IOException 286 { 287 _isAutomaticMethod = false; 288 setPretty(true); 289 290 ((QAbstractNode) node).print(this); 291 292 flush(); 293 } 294 295 301 public String printString(Node node) 302 throws IOException 303 { 304 CharBuffer cb = CharBuffer.allocate(); 305 306 _os = Vfs.openWrite(cb); 307 init(_os); 308 try { 309 ((QAbstractNode) node).print(this); 310 } finally { 311 flush(); 312 _os.close(); 313 } 314 315 return cb.close(); 316 } 317 318 324 public void setEscaping(boolean escapeText) 325 { 326 if (! _isText) 327 _escapeText = escapeText; 328 } 329 330 336 public boolean getEscaping() 337 { 338 return _escapeText; 339 } 340 341 344 public void setMethod(String method) 345 { 346 _method = method; 347 348 if (method == null) { 349 _isAutomaticMethod = true; 350 _isHtml = false; 351 } else if (method.equals("html")) { 352 _isAutomaticMethod = false; 353 _isHtml = true; 354 if (_isAutomaticPretty) 355 _isPretty = true; 356 } else if (method.equals("text")) { 357 _isAutomaticMethod = false; 358 _isText = true; 359 _escapeText = false; 360 } else { 361 _isAutomaticMethod = false; 362 _isHtml = false; 363 } 364 } 365 366 371 public void setVersion(String version) 372 { 373 _version = version; 374 } 375 376 381 public void setEncoding(String encoding) 382 { 383 _encoding = encoding; 384 try { 385 if (encoding != null) { 386 _os.setEncoding(encoding); 387 388 if (encoding.equals("US-ASCII") || encoding.equals("ISO-8859-1")) 389 _entities = XmlLatin1Entities.create(); 390 else 391 _entities = XmlEntities.create(); 392 } 393 } catch (Exception e) { 394 } 395 } 396 397 public void setMimeType(String mimeType) 398 { 399 _mimeType = mimeType; 400 if (_method == null && mimeType != null && mimeType.equals("text/html")) 401 setMethod("html"); 402 } 403 404 407 public void setJSP(boolean isJsp) 408 { 409 _isJsp = isJsp; 410 } 411 412 415 public boolean isJSP() 416 { 417 return _isJsp; 418 } 419 420 423 boolean isHtml() 424 { 425 return _isHtml; 426 } 427 428 434 public void setPretty(boolean isPretty) 435 { 436 _isPretty = isPretty; 437 _isAutomaticPretty = false; 438 } 439 440 443 public boolean isPretty() 444 { 445 return _isPretty; 446 } 447 448 public void setPrintDeclaration(boolean printDeclaration) 449 { 450 _printDeclaration = printDeclaration; 451 } 452 453 boolean getPrintDeclaration() 454 { 455 return _printDeclaration; 456 } 457 458 public void setStandalone(String standalone) 459 { 460 _standalone = standalone; 461 } 462 463 String getStandalone() 464 { 465 return _standalone; 466 } 467 468 public void setSystemId(String id) 469 { 470 _systemId = id; 471 } 472 473 String getSystemId() 474 { 475 return _systemId; 476 } 477 478 482 public void setIncludeContentType(boolean include) 483 { 484 _includeContentType = include; 485 } 486 487 491 public boolean getIncludeContentType() 492 { 493 return _includeContentType; 494 } 495 496 public void setPublicId(String id) 497 { 498 _publicId = id; 499 } 500 501 String getPublicId() 502 { 503 return _publicId; 504 } 505 506 public Path getPath() 507 { 508 if (_os instanceof WriteStream) 509 return ((WriteStream) _os).getPath(); 510 else 511 return null; 512 } 513 514 517 public void setLineMap(String filename) 518 { 519 _lineMap = new LineMap(filename); 520 } 521 522 public LineMap getLineMap() 523 { 524 return _lineMap; 525 } 526 527 public void addCdataElement(String elt) 528 { 529 if (_cdataElements == null) 530 _cdataElements = new HashMap <String ,String >(); 531 _cdataElements.put(elt, ""); 532 } 533 534 public void print(Node node) 535 throws IOException 536 { 537 if (node instanceof QAbstractNode) 538 ((QAbstractNode) node).print(this); 539 else { 540 printNode(node); 541 } 542 543 if (_isEnclosedStream) 544 _os.flush(); 545 } 546 547 public void printNode(Node node) 548 throws IOException 549 { 550 if (node == null) 551 return; 552 553 switch (node.getNodeType()) { 554 case Node.DOCUMENT_NODE: 555 startDocument((Document) node); 556 for (Node child = node.getFirstChild(); 557 child != null; 558 child = child.getNextSibling()) 559 printNode(child); 560 endDocument(); 561 break; 562 563 case Node.ELEMENT_NODE: { 564 Element elt = (Element) node; 565 566 startElement(elt.getNamespaceURI(), 567 elt.getLocalName(), 568 elt.getNodeName()); 569 570 NamedNodeMap attrs = elt.getAttributes(); 571 int len = attrs.getLength(); 572 for (int i = 0; i < len; i++) { 573 Attr attr = (Attr) attrs.item(i); 574 575 attribute(attr.getNamespaceURI(), 576 attr.getLocalName(), 577 attr.getNodeName(), 578 attr.getNodeValue()); 579 } 580 581 for (Node child = node.getFirstChild(); 582 child != null; 583 child = child.getNextSibling()) { 584 printNode(child); 585 } 586 endElement(elt.getNamespaceURI(), elt.getLocalName(), elt.getNodeName()); 587 break; 588 } 589 590 case Node.TEXT_NODE: 591 case Node.CDATA_SECTION_NODE: 592 { 593 CharacterData text = (CharacterData) node; 594 text(text.getData()); 595 break; 596 } 597 598 case Node.COMMENT_NODE: 599 { 600 Comment comment = (Comment) node; 601 comment(comment.getData()); 602 break; 603 } 604 605 case Node.PROCESSING_INSTRUCTION_NODE: 606 { 607 ProcessingInstruction pi = (ProcessingInstruction) node; 608 processingInstruction(pi.getNodeName(), pi.getData()); 609 break; 610 } 611 } 612 } 613 614 WriteStream getStream() 615 { 616 return _os; 617 } 618 619 public void startDocument(Document document) 620 throws IOException 621 { 622 _currentDocument = document; 623 624 startDocument(); 625 } 626 627 630 public void startDocument() 631 throws IOException 632 { 633 _isTop = true; 634 } 635 636 639 public void endDocument() 640 throws IOException 641 { 642 if (_isPretty && _lastTextChar < SPACE) 643 println(); 644 645 flush(); 646 } 647 648 651 public void setDocumentLocator(Locator locator) 652 { 653 _locator = (ExtendedLocator) locator; 654 } 655 656 663 public void setLocation(String filename, int line, int column) 664 { 665 _srcFilename = filename; 666 _srcLine = line; 667 } 668 669 676 public void startElement(String url, String localName, String qName) 677 throws IOException 678 { 679 if (_isText) 680 return; 681 682 if (_isAutomaticMethod) { 683 _isHtml = (qName.equalsIgnoreCase("html") && 684 (url == null || url.equals(""))); 685 686 if (_isAutomaticPretty) 687 _isPretty = _isHtml; 688 689 _isAutomaticMethod = false; 690 } 691 692 if (_isTop) 693 printHeader(qName); 694 695 if (_currentElement != null) 696 completeOpenTag(); 697 698 _attributeNames.clear(); 699 _attributeValues.clear(); 700 701 if (_isHtml && _verbatimTags.get(qName.toLowerCase()) != null) 702 _inVerbatim = true; 703 704 if (_isPretty && _preCount <= 0) 705 printPrettyStart(qName); 706 707 if (_lineMap == null) { 708 } 709 else if (_locator != null) { 710 _lineMap.add(_locator.getFilename(), _locator.getLineNumber(), _line); 711 } 712 else if (_srcFilename != null) 713 _lineMap.add(_srcFilename, _srcLine, _line); 714 715 print('<'); 716 print(qName); 717 _currentElement = qName; 718 _lastTextChar = NULL_SPACE; 719 } 720 721 726 public void printHeader(String top) 727 throws IOException 728 { 729 if (! _isTop) 730 return; 731 732 _isTop = false; 733 734 String encoding = _encoding; 735 736 if (encoding != null && encoding.equalsIgnoreCase("UTF-16")) 737 print('\ufeff'); 738 739 if (_isHtml) { 740 double dVersion = 4.0; 741 742 if (_version == null || _version.compareTo("4.0") >= 0) { 743 } 744 else { 745 dVersion = 3.2; 746 } 747 748 if (_systemId != null || _publicId != null) 749 printDoctype("html"); 750 751 if (encoding == null || encoding.equalsIgnoreCase("ISO-8859-1")) 752 _entities = HtmlEntities.create(dVersion); 754 else if (encoding.equalsIgnoreCase("US-ASCII")) 755 _entities = HtmlEntities.create(dVersion); 756 else 757 _entities = OtherEntities.create(dVersion); 758 } 759 else { 760 if (_printDeclaration) { 761 String version = _version; 762 763 if (version == null) 764 version = "1.0"; 765 766 print("<?xml version=\""); 767 print(version); 768 print("\""); 769 770 if (encoding == null || 771 encoding.equals("") || 772 encoding.equalsIgnoreCase("UTF-16") || 773 encoding.equalsIgnoreCase("US-ASCII")) { 774 } 775 else 776 print(" encoding=\"" + encoding + "\""); 777 778 if (_standalone != null && 779 (_standalone.equals("true") || _standalone.equals("yes"))) 780 print(" standalone=\"yes\""); 781 782 println("?>"); 783 } 784 785 printDoctype(top); 786 787 if (encoding == null || 788 encoding.equalsIgnoreCase("US-ASCII") || 789 encoding.equalsIgnoreCase("ISO-8859-1")) 790 _entities = XmlLatin1Entities.create(); 791 else 792 _entities = XmlEntities.create(); 793 } 794 795 _lastTextChar = NEWLINE; 796 } 797 798 803 private void printDoctype(String topElt) 804 throws IOException 805 { 806 if (_publicId != null && _systemId != null) 807 println("<!DOCTYPE " + topElt + " PUBLIC \"" + _publicId + "\" \"" + 808 _systemId + "\">"); 809 else if (_publicId != null) 810 println("<!DOCTYPE " + topElt + " PUBLIC \"" + _publicId + "\">"); 811 else if (_systemId != null) 812 println("<!DOCTYPE " + topElt + " SYSTEM \"" + _systemId + "\">"); 813 else if (_currentDocument instanceof QDocument) { 814 QDocumentType dtd = (QDocumentType) _currentDocument.getDoctype(); 815 816 if (dtd != null && dtd.getName() != null && dtd.getParentNode() == null) { 817 dtd.print(this); 818 println(); 819 } 820 } 821 } 822 823 public void startPrefixMapping(String prefix, String uri) 824 throws IOException 825 { 826 } 827 828 public void endPrefixMapping(String prefix) 829 throws IOException 830 { 831 } 832 833 838 private void printPrettyStart(String qName) 839 throws IOException 840 { 841 int code = _isHtml ? _prettyMap.get(qName.toLowerCase()) : -1; 842 843 if (code == NO_PRETTY) { 844 if (_lastTextChar == OMITTED_NEWLINE) 845 println(); 846 else if (_lastTextChar == OMITTED_SPACE) 847 print(' '); 848 } 849 else if (code != INLINE && _lastTextChar < WHITESPACE) { 850 if (_lastTextChar != NEWLINE) 851 println(); 852 for (int i = 0; i < _indent; i++) 853 print(' '); 854 } 855 else if (code == INLINE && _lastTextChar < WHITESPACE) { 856 if (_lastTextChar == OMITTED_NEWLINE) 857 println(); 858 else if (_lastTextChar == OMITTED_SPACE) 859 print(' '); 860 } 861 862 if (! _isHtml || code < 0) { 863 _indent += 2; 864 } 865 866 if (code == PRE) { 867 _preCount++; 868 _lastTextChar = 'a'; 869 } 870 else if (code == NO_PRETTY || code == INLINE) 871 _lastTextChar = 'a'; 872 else 873 _lastTextChar = NULL_SPACE; 874 } 875 876 884 public void attribute(String uri, String localName, String qName, 885 String value) 886 throws IOException 887 { 888 if (_isText) 889 return; 890 891 if (_currentElement != null) { 892 } 893 else if (qName.equals("encoding")) { 894 _encoding = value; 895 return; 896 } 897 else if (qName.startsWith("xmlns")) { 898 } 899 else 900 throw new IOException (L.l("attribute `{0}' outside element.", qName)); 901 902 qName = qName.intern(); 903 904 if (qName.startsWith("xmlns")) { 905 if (localName == null) 906 localName = ""; 907 908 if (_isHtml && localName.equals("") && value.equals("")) 909 return; 910 911 _namespace.put(localName, value); 912 if (_prefixList == null) 913 _prefixList = new ArrayList <String >(); 914 if (! _prefixList.contains(localName)) 915 _prefixList.add(localName); 916 return; 917 } 918 else if (qName.equals("xtp:jsp-attribute")) { 919 _attributeNames.add("<%= " + value + "%>"); 920 _attributeValues.add(null); 921 return; 922 } 923 924 if (_isHtml && ! _hasMetaContentType && 925 _currentElement.equals("meta") && 926 qName.equalsIgnoreCase("http-equiv") && 927 value.equalsIgnoreCase("content-type")) { 928 _hasMetaContentType = true; 929 } 930 931 for (int i = 0; i < _attributeNames.size(); i++) { 932 String oldName = _attributeNames.get(i); 933 934 if (oldName == qName) { 935 _attributeValues.set(i, value); 936 return; 937 } 938 } 939 940 if (qName == null || qName.equals("")) 941 throw new NullPointerException (); 942 943 _attributeNames.add(qName); 944 _attributeValues.add(value); 945 } 946 947 950 public boolean finishAttributes() 951 throws IOException 952 { 953 if (_currentElement == null) 954 return false; 955 956 for (int i = 0; i < _attributeNames.size(); i++) { 957 String qName = _attributeNames.get(i); 958 String value = _attributeValues.get(i); 959 960 if (_isHtml && 961 _booleanAttrs.get(qName.toLowerCase()) != null && 962 (value == null || value.equals("") || value.equals(qName))) { 963 print(' '); 964 print(qName); 965 } 966 else { 967 print(' '); 968 print(qName); 969 970 if (value != null) { 971 print("=\""); 972 973 if (! _escapeText || _inVerbatim) 974 print(value); 975 991 else { 992 int len = value.length(); 993 int offset = 0; 994 995 while (len > _abuf.length) { 996 value.getChars(offset, offset + _abuf.length, _abuf, 0); 997 _entities.printText(this, _abuf, 0, _abuf.length, true); 998 len -= _abuf.length; 999 offset += _abuf.length; 1000 } 1001 1002 value.getChars(offset, offset + len, _abuf, 0); 1003 _entities.printText(this, _abuf, 0, len, true); 1004 } 1005 print('\"'); 1006 } 1007 else if (! _isHtml) { 1008 print("=\"\""); 1009 } 1010 } 1011 } 1012 1013 if (_prefixList != null && _prefixList.size() > 0) { 1014 for (int i = 0; i < _prefixList.size(); i++) { 1015 String prefix = _prefixList.get(i); 1016 String url = _namespace.get(prefix); 1017 1018 if (prefix.equals("")) { 1019 print(" xmlns=\""); 1020 print(url); 1021 print('\"'); 1022 } 1023 else if (prefix.startsWith("xmlns")) { 1024 print(" "); 1025 print(prefix); 1026 print("=\""); 1027 print(url); 1028 print('\"'); 1029 } 1030 else { 1031 print(" xmlns:"); 1032 print(prefix); 1033 print("=\""); 1034 print(url); 1035 print('\"'); 1036 } 1037 } 1038 1039 _prefixList.clear(); 1040 _namespace.clear(); 1041 } 1042 1043 _currentElement = null; 1044 1046 return true; 1047 } 1048 1049 1056 public void endElement(String uri, String localName, String qName) 1057 throws IOException 1058 { 1059 if (_isText) 1060 return; 1061 1062 String normalName = _isHtml ? qName.toLowerCase() : qName; 1063 1064 if (_isHtml && _verbatimTags.get(normalName) != null) 1065 _inVerbatim = false; 1066 1067 int prevTextChar = _lastTextChar; 1068 boolean isEmpty = _currentElement != null; 1069 if (_currentElement != null) 1070 finishAttributes(); 1071 1072 if (! _isHtml || _hasMetaContentType) { 1073 } 1074 else if (normalName.equals("head")) { 1075 if (isEmpty) 1076 print(">"); 1077 isEmpty = false; 1078 printMetaContentType(); 1079 _currentElement = null; 1080 } 1081 1082 if (isEmpty) { 1083 if (_isHtml && _empties.get(normalName) >= 0) 1084 print(">"); 1085 else if (prevTextChar <= OMITTED) { 1086 print(">"); 1087 printPrettyEnd(qName); 1088 print("</"); 1089 print(qName); 1090 print(">"); 1091 return; 1092 } 1093 else if (_isHtml) { 1094 print("></"); 1095 print(qName); 1096 print(">"); 1097 } 1098 else { 1099 print("/>"); 1100 } 1101 1102 if (_isPretty) 1103 closePretty(qName); 1104 } 1105 else if (_isHtml && _empties.get(normalName) >= 0 && 1106 ! normalName.equals("p")) { 1107 if (_isPretty) 1108 closePretty(qName); 1109 } 1110 else if (_isPretty) { 1111 printPrettyEnd(qName); 1112 print("</"); 1113 print(qName); 1114 print(">"); 1115 } 1116 else { 1117 print("</"); 1118 print(qName); 1119 print(">"); 1120 } 1121 1122 _currentElement = null; 1123 } 1124 1125 1128 private void printPrettyEnd(String qName) 1129 throws IOException 1130 { 1131 int code = _isHtml ? _prettyMap.get(qName.toLowerCase()) : -1; 1132 1133 if (code == PRE) { 1134 _preCount--; 1135 _lastTextChar = NULL_SPACE; 1136 return; 1137 } 1138 else if (_preCount > 0) { 1139 return; 1140 } 1141 else if (code == NO_PRETTY) { 1142 if (_lastTextChar <= OMITTED) 1143 println(); 1144 _lastTextChar = 'a'; 1145 return; 1147 } 1148 else if (code == INLINE) { 1149 _lastTextChar = NULL_SPACE; 1150 return; 1151 } 1152 1153 if (! _isHtml || code < 0) { 1154 _indent -= 2; 1155 } 1156 1157 if (_lastTextChar <= WHITESPACE) { 1158 if (_lastTextChar != NEWLINE) 1159 println(); 1160 for (int i = 0; i < _indent; i++) 1161 print(' '); 1162 } 1163 _lastTextChar = NULL_SPACE; 1164 } 1165 1166 1169 private void closePretty(String qName) 1170 { 1171 int code = _isHtml ? _prettyMap.get(qName.toLowerCase()) : -1; 1172 1173 if (code == PRE) { 1174 _preCount--; 1175 _lastTextChar = NULL_SPACE; 1176 return; 1177 } 1178 if (_preCount > 0) 1179 return; 1180 1181 if (! _isHtml || code < 0) { 1182 _indent -= 2; 1183 } 1184 1185 if (code != NO_PRETTY) 1186 _lastTextChar = NULL_SPACE; 1187 else 1188 _lastTextChar = 'a'; 1189 } 1190 1191 1197 public void processingInstruction(String name, String data) 1198 throws IOException 1199 { 1200 if (_isText) 1201 return; 1202 1203 if (_currentElement != null) 1204 completeOpenTag(); 1205 1206 if (_isTop && ! _isHtml && ! _isAutomaticMethod) { 1207 printHeader(null); 1208 _isTop = false; 1209 } 1210 1211 print("<?"); 1212 print(name); 1213 1214 if (data != null && data.length() > 0) { 1215 print(" "); 1216 print(data); 1217 } 1218 1219 if (isHtml()) 1220 print(">"); 1221 else 1222 print("?>"); 1223 1224 _lastTextChar = NULL_SPACE; 1225 } 1226 1227 1232 public void comment(String data) 1233 throws IOException 1234 { 1235 if (_isText) 1236 return; 1237 1238 int textChar = _lastTextChar; 1239 1240 if (_currentElement != null) 1241 completeOpenTag(); 1242 1243 if (_isPretty && _preCount <= 0 && 1244 (textChar == OMITTED_NEWLINE || textChar == NULL_SPACE)) { 1245 println(); 1246 1247 for (int i = 0; i < _indent; i++) 1248 print(' '); 1249 } 1250 1251 print("<!--"); 1252 print(data); 1253 print("-->"); 1254 1255 _lastTextChar = NULL_SPACE; 1256 } 1257 1258 1261 public boolean getEscapeText() 1262 { 1263 return _escapeText; 1264 } 1265 1266 1270 public void setEscapeText(boolean isEscaped) 1271 { 1272 _escapeText = isEscaped; 1273 } 1274 1275 1279 public void text(String text) 1280 throws IOException 1281 { 1282 int length = text.length(); 1283 1284 for (int offset = 0; offset < length; offset += _cbuf.length) { 1285 int sublen = length - offset; 1286 if (sublen > _cbuf.length) 1287 sublen = _cbuf.length; 1288 1289 text.getChars(offset, offset + sublen, _cbuf, 0); 1290 text(_cbuf, 0, sublen); 1291 } 1292 } 1293 1294 1298 public void text(char []buffer, int offset, int length) 1299 throws IOException 1300 { 1301 if (length == 0) 1302 return; 1303 1304 int prevTextChar = _lastTextChar; 1305 if ((_isPretty && _preCount <= 0 || _isTop) && ! _isText && 1306 trimPrettyWhitespace(buffer, offset, length)) { 1307 if (prevTextChar <= WHITESPACE) 1308 return; 1309 if (_lastTextChar == OMITTED_SPACE) 1310 _lastTextChar = SPACE; 1311 if (_lastTextChar == OMITTED_NEWLINE) 1312 _lastTextChar = NEWLINE; 1313 } 1314 1315 int nextTextChar = _lastTextChar; 1316 if (_currentElement != null) { 1317 completeOpenTag(); 1318 1319 if (_isPretty && _preCount <= 0 && prevTextChar <= OMITTED) 1320 println(); 1321 } 1322 1323 _lastTextChar = nextTextChar; 1324 1325 if (! _isTop) { 1326 } 1327 else if (! _isJsp) { 1328 _isTop = false; 1329 } 1330 else if (_isAutomaticMethod) { 1331 } 1332 else if (! _isHtml) { 1333 printHeader(null); 1334 _isTop = false; 1335 } 1336 1337 if (_isHtml && ! _hasMetaContentType && ! _inHead) { 1338 int textChar = _lastTextChar; 1339 1340 if (_isPretty && _preCount <= 0 && prevTextChar <= OMITTED) 1341 println(); 1342 1343 _lastTextChar = textChar; 1345 prevTextChar = 'a'; 1346 } 1347 1348 if (! _isPretty || _preCount > 0) { 1349 } 1350 else if (prevTextChar == OMITTED_NEWLINE) { 1351 if (buffer[offset] != '\n') 1352 println(); 1353 } 1354 else if (prevTextChar == OMITTED_SPACE) { 1355 char ch = buffer[offset]; 1356 1357 if (ch != ' ' && ch != '\n') 1358 print(' '); 1359 } 1360 1361 if (_lineMap == null) { 1362 } 1363 else if (_locator != null) { 1364 _lineMap.add(_locator.getFilename(), _locator.getLineNumber(), _line); 1365 } 1366 else if (_srcFilename != null) 1367 _lineMap.add(_srcFilename, _srcLine, _line); 1368 1369 if (! _escapeText || _inVerbatim || _entities == null) 1370 print(buffer, offset, length); 1371 else 1372 _entities.printText(this, buffer, offset, length, false); 1373 } 1374 1375 1378 boolean trimPrettyWhitespace(char []buffer, int offset, int length) 1379 { 1380 char textChar = 'a'; 1381 int i = length - 1; 1382 1383 for (; i >= 0; i--) { 1384 char ch = buffer[offset + i]; 1385 1386 if (ch == '\r' || ch == '\n') { 1387 if (textChar != NEWLINE) 1388 textChar = OMITTED_NEWLINE; 1389 } 1390 else if (ch == ' ' || ch == '\t') { 1391 if (textChar == 'a' || textChar == NULL_SPACE) 1392 textChar = OMITTED_SPACE; 1393 } 1394 else if (textChar == OMITTED_NEWLINE) { 1395 textChar = NEWLINE; 1396 break; 1397 } 1398 else if (textChar == OMITTED_SPACE) { 1399 textChar = SPACE; 1400 break; 1401 } 1402 else 1403 break; 1404 } 1405 1406 _lastTextChar = textChar; 1407 1408 return (i < 0 && textChar <= WHITESPACE); 1409 } 1410 1411 public void cdata(String text) 1412 throws IOException 1413 { 1414 if (text.length() == 0) 1415 return; 1416 1417 _isTop = false; 1418 1419 if (_currentElement != null) 1420 completeOpenTag(); 1421 1422 if (_lineMap != null && _srcFilename != null) 1423 _lineMap.add(_srcFilename, _srcLine, _line); 1424 1425 print("<![CDATA["); 1426 1427 print(text); 1428 1429 print("]]>"); 1430 1431 _lastTextChar = NEWLINE; 1432 } 1433 1434 private void completeOpenTag() 1435 throws IOException 1436 { 1437 boolean isHead = (_isHtml && ! _hasMetaContentType && 1438 _currentElement.equalsIgnoreCase("head")); 1439 1440 finishAttributes(); 1441 print(">"); 1442 1443 if (isHead) 1444 printHeadContentType(); 1445 } 1446 1447 public void cdata(char []buffer, int offset, int length) 1448 throws IOException 1449 { 1450 cdata(new String (buffer, offset, length)); 1451 } 1452 1453 private void printHeadContentType() 1454 throws IOException 1455 { 1456 printMetaContentType(); 1457 } 1458 1459 private void printMetaContentType() 1460 throws IOException 1461 { 1462 if (! _includeContentType) 1463 return; 1464 1465 _hasMetaContentType = true; 1466 if (_lastTextChar != NEWLINE) 1467 println(); 1468 1469 if (_encoding == null || _encoding.equals("US-ASCII")) 1470 _encoding = "ISO-8859-1"; 1471 String mimeType = _mimeType; 1472 if (mimeType == null) 1473 mimeType = "text/html"; 1474 1475 println(" <meta http-equiv=\"Content-Type\" content=\"" + 1476 mimeType + "; charset=" + _encoding + "\">"); 1477 _lastTextChar = NEWLINE; 1478 } 1479 1480 void printDecl(String text) throws IOException 1481 { 1482 for (int i = 0; i < text.length(); i++) { 1483 char ch = text.charAt(i); 1484 1485 switch (ch) { 1486 case '&': 1487 if (i + 1 < text.length() && text.charAt(i + 1) == '#') 1488 print("&"); 1489 else 1490 print(ch); 1491 break; 1492 1493 case '"': 1494 print("""); 1495 break; 1496 1497 case '\'': 1498 print("'"); 1499 break; 1500 1501 case '\n': 1502 print("\n"); 1503 break; 1504 1505 default: 1506 print(ch); 1507 } 1508 } 1509 } 1510 1511 1514 void println() throws IOException 1515 { 1516 print('\n'); 1517 } 1518 1519 void println(String text) throws IOException 1520 { 1521 print(text); 1522 println(); 1523 } 1524 1525 1528 void print(char []buf) 1529 throws IOException 1530 { 1531 print(buf, 0, buf.length); 1532 } 1533 1534 1537 void print(char []buf, int off, int len) 1538 throws IOException 1539 { 1540 for (int i = 0; i < len; i++) 1541 print(buf[off + i]); 1542 } 1543 1544 1547 void print(String text) throws IOException 1548 { 1549 int len = text.length(); 1550 1551 for (int i = 0; i < len; i++) { 1552 char ch = text.charAt(i); 1553 print(ch); 1554 } 1555 } 1556 1557 1560 void print(char ch) throws IOException 1561 { 1562 if (_capacity <= _length) { 1563 _os.print(_buffer, 0, _length); 1564 _length = 0; 1565 } 1566 1567 _buffer[_length++] = ch; 1568 if (ch == '\n') 1569 _line++; 1570 } 1571 1572 1575 void print(int i) throws IOException 1576 { 1577 if (i < 0) { 1578 } 1579 else if (i < 10) { 1580 print((char) ('0' + i)); 1581 return; 1582 } 1583 else if (i < 100) { 1584 print((char) ('0' + i / 10)); 1585 print((char) ('0' + i % 10)); 1586 return; 1587 } 1588 1589 if (_length >= 0) { 1590 _os.print(_buffer, 0, _length); 1591 _length = 0; 1592 } 1593 1594 _os.print(i); 1595 } 1596 1597 private void flush() throws IOException 1598 { 1599 if (_length >= 0) { 1600 _os.print(_buffer, 0, _length); 1601 _length = 0; 1602 } 1603 1604 if (_isEnclosedStream) 1605 _os.flush(); 1606 } 1607 1608 private void close() throws IOException 1609 { 1610 flush(); 1611 1612 if (_isEnclosedStream) 1613 _os.close(); 1614 } 1615 1616 1617 static void add(IntMap map, String name, int value) 1618 { 1619 map.put(name, value); 1620 map.put(name.toUpperCase(), value); 1621 } 1622 1623 static void add(HashMap <String ,String > map, String name) 1624 { 1625 map.put(name, name); 1626 map.put(name.toUpperCase(), name); 1627 } 1628 1629 static { 1630 _empties = new IntMap(); 1631 add(_empties, "basefont", ALWAYS_EMPTY); 1632 add(_empties, "br", ALWAYS_EMPTY); 1633 add(_empties, "area", ALWAYS_EMPTY); 1634 add(_empties, "link", ALWAYS_EMPTY); 1635 add(_empties, "img", ALWAYS_EMPTY); 1636 add(_empties, "param", ALWAYS_EMPTY); 1637 add(_empties, "hr", ALWAYS_EMPTY); 1638 add(_empties, "input", ALWAYS_EMPTY); 1639 add(_empties, "col", ALWAYS_EMPTY); 1640 add(_empties, "frame", ALWAYS_EMPTY); 1641 add(_empties, "isindex", ALWAYS_EMPTY); 1642 add(_empties, "base", ALWAYS_EMPTY); 1643 add(_empties, "meta", ALWAYS_EMPTY); 1644 1645 add(_empties, "p", ALWAYS_EMPTY); 1646 add(_empties, "li", ALWAYS_EMPTY); 1647 1648 add(_empties, "option", EMPTY_IF_EMPTY); 1649 1650 _booleanAttrs = new HashMap <String ,String >(); 1651 add(_booleanAttrs, "checked"); 1653 add(_booleanAttrs, "compact"); 1655 add(_booleanAttrs, "declare"); 1657 add(_booleanAttrs, "defer"); 1659 add(_booleanAttrs, "disabled"); 1661 add(_booleanAttrs, "ismap"); 1663 add(_booleanAttrs, "multiple"); 1665 add(_booleanAttrs, "nohref"); 1667 add(_booleanAttrs, "noresize"); 1669 add(_booleanAttrs, "noshade"); 1671 add(_booleanAttrs, "nowrap"); 1673 add(_booleanAttrs, "readonly"); 1675 add(_booleanAttrs, "selected"); 1677 1678 _prettyMap = new IntMap(); 1679 add(_prettyMap, "img", NO_PRETTY); 1681 add(_prettyMap, "a", NO_PRETTY); 1682 add(_prettyMap, "embed", NO_PRETTY); 1683 add(_prettyMap, "th", NO_PRETTY); 1684 add(_prettyMap, "td", NO_PRETTY); 1685 add(_prettyMap, "tt", INLINE); 1687 add(_prettyMap, "i", INLINE); 1688 add(_prettyMap, "b", INLINE); 1689 add(_prettyMap, "big", INLINE); 1690 add(_prettyMap, "em", INLINE); 1691 add(_prettyMap, "string", INLINE); 1692 add(_prettyMap, "dfn", INLINE); 1693 add(_prettyMap, "code", INLINE); 1694 add(_prettyMap, "samp", INLINE); 1695 add(_prettyMap, "kbd", INLINE); 1696 add(_prettyMap, "var", INLINE); 1697 add(_prettyMap, "cite", INLINE); 1698 add(_prettyMap, "abbr", INLINE); 1699 add(_prettyMap, "acronym", INLINE); 1700 add(_prettyMap, "object", INLINE); 1701 add(_prettyMap, "q", INLINE); 1702 add(_prettyMap, "sub", INLINE); 1703 add(_prettyMap, "sup", INLINE); 1704 add(_prettyMap, "font", INLINE); 1705 add(_prettyMap, "small", INLINE); 1706 add(_prettyMap, "span", INLINE); 1707 add(_prettyMap, "bdo", INLINE); 1708 add(_prettyMap, "jsp:expression", INLINE); 1709 1710 add(_prettyMap, "textarea", PRE); 1711 add(_prettyMap, "pre", PRE); 1712 1713 add(_prettyMap, "html", NO_INDENT); 1714 add(_prettyMap, "body", NO_INDENT); 1715 add(_prettyMap, "ul", NO_INDENT); 1716 add(_prettyMap, "table", NO_INDENT); 1717 add(_prettyMap, "frameset", NO_INDENT); 1718 1719 _verbatimTags = new HashMap <String ,String >(); 1720 add(_verbatimTags, "script"); 1721 add(_verbatimTags, "style"); 1722 } 1723} 1724 | Popular Tags |