1 4 package org.znerd.xmlenc; 5 6 import java.io.IOException ; 7 import java.io.UnsupportedEncodingException ; 8 import java.io.Writer ; 9 10 80 public class XMLOutputter 81 extends Object 82 implements StatefulXMLEventListener { 83 84 88 92 96 public static final String DEFAULT_INDENTATION = ""; 97 98 99 103 107 public XMLOutputter() { 108 _elementStack = new String [16]; 109 _quotationMark = '"'; 110 } 111 112 137 public XMLOutputter(Writer out, String encoding) 138 throws IllegalStateException , 139 IllegalArgumentException , 140 UnsupportedEncodingException { 141 142 this(); 143 144 reset(out, encoding); 146 } 147 148 149 171 public XMLOutputter(Writer out, XMLEncoder encoder) 172 throws IllegalStateException , 173 IllegalArgumentException , 174 UnsupportedEncodingException { 175 176 this(); 177 178 reset(out, encoder); 180 } 181 182 186 194 private Writer _out; 195 196 199 private XMLEncoder _encoder; 200 201 204 private XMLEventListenerState _state = UNINITIALIZED; 205 206 214 private String [] _elementStack; 215 216 222 private int _elementStackSize; 223 224 231 private char _quotationMark; 232 233 236 private boolean _escapeAmpersands = true; 237 238 242 private LineBreak _lineBreak = LineBreak.NONE; 243 244 248 private char[] _lineBreakChars = _lineBreak._lineBreakChars; 249 250 254 private String _indentation; 255 256 257 261 268 private final void checkInvariants() 269 throws Error { 270 } 272 273 279 private final void writeIndentation() 280 throws IOException { 281 282 if (_indentation.length() != 0) { 284 int count = _elementStackSize - 1; 285 for (int i = 0; i < count; i++) { 286 _out.write(_indentation); 287 } 288 } 289 } 290 291 298 public final Writer getWriter() { 299 return _out; 300 } 301 302 309 public final String getEncoding() { 310 if (_encoder == null) { 311 return null; 312 } else { 313 return _encoder.getEncoding(); 314 } 315 } 316 317 324 public void reset() { 325 _out = null; 326 _encoder = null; 327 _elementStackSize = 0; 328 _state = UNINITIALIZED; 329 _lineBreak = LineBreak.NONE; 330 _lineBreakChars = _lineBreak._lineBreakChars; 331 _indentation = DEFAULT_INDENTATION; 332 333 checkInvariants(); 335 } 336 337 348 private final void reset(Writer out) 349 throws IllegalArgumentException { 350 351 if (out == null) { 353 throw new IllegalArgumentException ("out == null"); 354 } 355 356 _out = out; 358 _state = BEFORE_XML_DECLARATION; 359 _elementStackSize = 0; 360 _lineBreak = LineBreak.NONE; 361 _lineBreakChars = _lineBreak._lineBreakChars; 362 _indentation = DEFAULT_INDENTATION; 363 364 checkInvariants(); 366 } 367 368 385 public final void reset(Writer out, String encoding) 386 throws IllegalArgumentException , 387 UnsupportedEncodingException { 388 389 if (encoding == null) { 391 throw new IllegalArgumentException ("encoding == null"); 392 } 393 394 reset(out); 395 396 _encoder = XMLEncoder.getEncoder(encoding); 398 399 checkInvariants(); 401 } 402 403 420 public final void reset(Writer out, XMLEncoder encoder) 421 throws IllegalArgumentException , 422 UnsupportedEncodingException { 423 424 if (encoder == null) { 426 throw new IllegalArgumentException ("encoder == null"); 427 } 428 429 reset(out); 430 431 _encoder = encoder; 433 434 checkInvariants(); 436 } 437 438 466 public final void setState(XMLEventListenerState newState, String [] newElementStack) 467 throws IllegalArgumentException { 468 469 if (newState == null) { 471 throw new IllegalArgumentException ("newState == null"); 472 } else if (newState == START_TAG_OPEN && newElementStack == null) { 473 throw new IllegalArgumentException ("newState == START_TAG_OPEN && newElementStack == null"); 474 } else if (newState == WITHIN_ELEMENT && newElementStack == null) { 475 throw new IllegalArgumentException ("newState == WITHIN_ELEMENT && newElementStack == null"); 476 } else if (newState != START_TAG_OPEN && newState != WITHIN_ELEMENT && newElementStack != null) { 477 throw new IllegalArgumentException ("newState != START_TAG_OPEN && newState != WITHIN_ELEMENT && newElementStack != null"); 478 } 479 480 if (newElementStack != null) { 481 for (int i = 0; i < newElementStack.length; i++) { 482 if (newElementStack[i] == null) { 483 throw new IllegalArgumentException ("newElementStack[" + i + "] == null"); 484 } 485 } 486 487 if (newElementStack.length > _elementStack.length) { 488 try { 489 _elementStack = new String [newElementStack.length + 16]; 490 } catch (OutOfMemoryError error) { 491 _elementStack = new String [newElementStack.length]; 492 } 493 } 494 System.arraycopy(newElementStack, 0, _elementStack, 0, newElementStack.length); 495 } 496 497 if (newState == UNINITIALIZED) { 498 reset(); 499 } else { 500 _state = newState; 501 _elementStackSize = newElementStack == null ? 0 : newElementStack.length; 502 } 503 504 checkInvariants(); 506 } 507 508 514 public final XMLEventListenerState getState() { 515 return _state; 516 } 517 518 530 public final boolean isEscaping() { 531 return _escapeAmpersands; 532 } 533 534 549 public final void setEscaping(boolean escapeAmpersands) { 550 _escapeAmpersands = escapeAmpersands; 551 552 checkInvariants(); 554 } 555 556 568 public final String [] getElementStack() { 569 if (_elementStackSize == 0) { 570 return null; 571 } else { 572 String [] newStack = new String [_elementStackSize]; 573 System.arraycopy(_elementStack, 0, newStack, 0, _elementStackSize); 574 return newStack; 575 } 576 } 577 578 586 public final int getElementStackSize() { 587 return _elementStackSize; 588 } 589 590 599 public final int getElementStackCapacity() { 600 return _elementStack.length; 601 } 602 603 617 public final void setElementStackCapacity(int newCapacity) 618 throws IllegalArgumentException , OutOfMemoryError { 619 620 if (newCapacity < _elementStack.length) { 622 throw new IllegalArgumentException ("newCapacity < getElementStackSize()"); 623 } 624 625 int currentCapacity = _elementStack.length; 626 627 if (currentCapacity == newCapacity) { 629 return; 630 } 631 632 String [] newStack = new String [newCapacity]; 633 System.arraycopy(_elementStack, 0, newStack, 0, _elementStackSize); 634 _elementStack = newStack; 635 636 checkInvariants(); 638 } 639 640 654 public final void setQuotationMark(char c) 655 throws IllegalArgumentException { 656 657 if (c == '\'' || c == '"') { 659 _quotationMark = c; 660 661 } else { 663 throw new IllegalArgumentException ("c != '\\'' && c != '\"'"); 664 } 665 666 checkInvariants(); 668 } 669 670 680 public final char getQuotationMark() { 681 return _quotationMark; 682 } 683 684 691 public final void setLineBreak(LineBreak lineBreak) { 692 _lineBreak = lineBreak != null 693 ? lineBreak 694 : LineBreak.NONE; 695 _lineBreakChars = _lineBreak._lineBreakChars; 696 697 checkInvariants(); 699 } 700 701 707 public final LineBreak getLineBreak() { 708 return _lineBreak; 709 } 710 711 718 public final void setIndentation(String indentation) { 719 _indentation = indentation != null 720 ? indentation 721 : DEFAULT_INDENTATION; 722 723 checkInvariants(); 725 } 726 727 733 public final String getIndentation() { 734 return _indentation; 735 } 736 737 743 private void closeStartTag() 744 throws IOException { 745 _out.write('>'); 746 } 747 748 765 public final void declaration() throws IllegalStateException , IOException { 766 767 if (_state != BEFORE_XML_DECLARATION) { 769 throw new IllegalStateException ("getState() == " + _state); 770 } 771 772 _state = ERROR_STATE; 775 776 _encoder.declaration(_out); 778 779 _out.write(_lineBreakChars); 781 782 _state = BEFORE_DTD_DECLARATION; 784 785 checkInvariants(); 787 } 788 789 842 public final void dtd(String name, String publicID, String systemID) 843 throws IllegalStateException , 844 IllegalArgumentException , 845 InvalidXMLException, 846 IOException { 847 848 if (_state != BEFORE_XML_DECLARATION 850 && _state != BEFORE_DTD_DECLARATION) { 851 throw new IllegalStateException ("getState() == " + _state); 852 } 853 854 if (name == null) { 856 throw new IllegalArgumentException ("name == null"); 857 } else if (publicID != null && systemID == null) { 858 throw new IllegalArgumentException ("Found public identifier, but no system identifier."); 859 } 860 861 XMLChecker.checkName(name); 863 865 _state = ERROR_STATE; 868 869 _out.write("<!DOCTYPE "); 871 _out.write(name); 872 if (publicID != null) { 873 _out.write(" PUBLIC \""); 874 _out.write(publicID); 875 _out.write('"'); 876 _out.write(' '); 877 _out.write('"'); 878 _out.write(systemID); 879 _out.write('"'); 880 } else if (systemID != null) { 881 _out.write(" SYSTEM \""); 882 _out.write(systemID); 883 _out.write('"'); 884 } 885 closeStartTag(); 886 887 _state = BEFORE_ROOT_ELEMENT; 889 890 checkInvariants(); 892 } 893 894 916 public final void startTag(String type) 917 throws IllegalStateException , IllegalArgumentException , IOException { 918 919 if (_state != BEFORE_XML_DECLARATION && 921 _state != BEFORE_DTD_DECLARATION && 922 _state != BEFORE_ROOT_ELEMENT && 923 _state != START_TAG_OPEN && 924 _state != WITHIN_ELEMENT) { 925 throw new IllegalStateException ("getState() == " + _state); 926 927 } else if (type == null) { 929 throw new IllegalArgumentException ("type == null"); 930 } 931 932 boolean startTagOpen = _state == START_TAG_OPEN; 933 934 _state = ERROR_STATE; 937 938 if (_elementStackSize == _elementStack.length) { 940 String [] newStack; 941 try { 942 newStack = new String [(_elementStackSize + 1) * 2]; 943 } catch (OutOfMemoryError error) { 944 newStack = new String [_elementStackSize + 1]; 945 } 946 System.arraycopy(_elementStack, 0, newStack, 0, _elementStackSize); 947 _elementStack = newStack; 948 } 949 950 _elementStack[_elementStackSize] = type; 952 _elementStackSize++; 953 954 if (startTagOpen) { 957 _out.write('>'); 958 } 959 960 _out.write(_lineBreakChars); 962 writeIndentation(); 963 964 _out.write('<'); 965 966 _out.write(type); 968 969 _state = START_TAG_OPEN; 971 972 checkInvariants(); 974 } 975 976 998 public final void attribute(String name, String value) 999 throws IllegalStateException , IllegalArgumentException , IOException { 1000 1001 if (getState() != START_TAG_OPEN) { 1003 throw new IllegalStateException ("getState() == " + _state); 1004 1005 } else if (name == null || value == null) { 1007 if (name == null && value == null) { 1008 throw new IllegalArgumentException ("name == null && value == null"); 1009 } else if (name == null) { 1010 throw new IllegalArgumentException ("name == null"); 1011 } else { 1012 throw new IllegalArgumentException ("value == null"); 1013 } 1014 } 1015 1016 _state = ERROR_STATE; 1019 1020 _encoder.attribute(_out, name, value, _quotationMark, _escapeAmpersands); 1022 1023 _state = START_TAG_OPEN; 1025 1026 checkInvariants(); 1028 } 1029 1030 1041 public final void endTag() 1042 throws IllegalStateException , IOException { 1043 1044 if (_state != WITHIN_ELEMENT 1046 && _state != START_TAG_OPEN) { 1047 throw new IllegalStateException ("getState() == " + _state); 1048 } 1049 1050 boolean startTagOpen = _state == START_TAG_OPEN; 1051 1052 _state = ERROR_STATE; 1055 1056 String type = _elementStack[_elementStackSize-1]; 1057 1058 if (startTagOpen) { 1060 _out.write('/'); 1061 _out.write('>'); 1062 _out.write(_lineBreakChars); 1063 } else { 1064 _out.write(_lineBreakChars); 1065 if (_lineBreak != LineBreak.NONE) { 1066 writeIndentation(); 1067 } 1068 1069 _out.write('<'); 1070 _out.write('/'); 1071 _out.write(type); 1072 closeStartTag(); 1073 } 1074 1075 _elementStackSize--; 1076 1077 if (_elementStackSize == 0) { 1079 _state = AFTER_ROOT_ELEMENT; 1080 } else { 1081 _state = WITHIN_ELEMENT; 1082 } 1083 1084 checkInvariants(); 1086 } 1087 1088 1108 public final void pcdata(String text) 1109 throws IllegalStateException , IllegalArgumentException , InvalidXMLException, IOException { 1110 1111 if (_state != START_TAG_OPEN 1113 && _state != WITHIN_ELEMENT) { 1114 throw new IllegalStateException ("getState() == " + _state); 1115 1116 } else if (text == null) { 1118 throw new IllegalArgumentException ("text == null"); 1119 } 1120 1121 boolean startTagOpen = _state == START_TAG_OPEN; 1122 1123 _state = ERROR_STATE; 1126 1127 if (startTagOpen) { 1129 closeStartTag(); 1130 _out.write(_lineBreakChars); 1131 } 1132 _encoder.text(_out, text, _escapeAmpersands); 1133 1134 _state = WITHIN_ELEMENT; 1136 1137 checkInvariants(); 1139 } 1140 1141 1175 public final void pcdata(char[] ch, int start, int length) 1176 throws IllegalStateException , IllegalArgumentException , IndexOutOfBoundsException , InvalidXMLException, IOException { 1177 1178 if (_state != START_TAG_OPEN 1180 && _state != WITHIN_ELEMENT) { 1181 throw new IllegalStateException ("getState() == " + _state); 1182 1183 } else if (ch == null) { 1185 throw new IllegalArgumentException ("ch == null"); 1186 } else if (start < 0) { 1187 throw new IllegalArgumentException ("start (" + start + ") < 0"); 1188 } else if (start >= ch.length) { 1189 throw new IllegalArgumentException ("start (" + start + ") >= ch.length (" + ch.length + ')'); 1190 } else if (length < 0) { 1191 throw new IllegalArgumentException ("length < 0"); 1192 } 1193 1194 boolean startTagOpen = _state == START_TAG_OPEN; 1195 1196 _state = ERROR_STATE; 1199 1200 if (startTagOpen) { 1202 closeStartTag(); 1203 } 1204 _encoder.text(_out, ch, start, length, _escapeAmpersands); 1205 1206 _state = WITHIN_ELEMENT; 1208 1209 checkInvariants(); 1211 } 1212 1213 1244 public final void whitespace(String whitespace) 1245 throws IllegalStateException , IllegalArgumentException , InvalidXMLException, IOException { 1246 1247 if (_state != BEFORE_XML_DECLARATION && 1249 _state != BEFORE_DTD_DECLARATION && 1250 _state != BEFORE_ROOT_ELEMENT && 1251 _state != START_TAG_OPEN && 1252 _state != WITHIN_ELEMENT && 1253 _state != AFTER_ROOT_ELEMENT) { 1254 throw new IllegalStateException ("getState() == " + _state); 1255 1256 } else if (whitespace == null) { 1258 throw new IllegalArgumentException ("whitespace == null"); 1259 } 1260 1261 XMLEventListenerState oldState = _state; 1262 1263 _state = ERROR_STATE; 1266 1267 if (oldState == START_TAG_OPEN) { 1269 closeStartTag(); 1270 } 1271 1272 _encoder.whitespace(_out, whitespace); 1274 1275 if (oldState == BEFORE_XML_DECLARATION) { 1277 _state = BEFORE_DTD_DECLARATION; 1278 } else if (oldState == START_TAG_OPEN) { 1279 _state = WITHIN_ELEMENT; 1280 } else { 1281 _state = oldState; 1282 } 1283 1284 checkInvariants(); 1286 } 1287 1288 1337 public final void whitespace(char[] ch, int start, int length) 1338 throws IllegalStateException , IllegalArgumentException , IndexOutOfBoundsException , InvalidXMLException, IOException { 1339 1340 if (_state != BEFORE_XML_DECLARATION 1342 && _state != BEFORE_DTD_DECLARATION 1343 && _state != BEFORE_ROOT_ELEMENT 1344 && _state != START_TAG_OPEN 1345 && _state != WITHIN_ELEMENT 1346 && _state != AFTER_ROOT_ELEMENT) { 1347 throw new IllegalStateException ("getState() == " + _state); 1348 1349 } else if (ch == null) { 1351 throw new IllegalArgumentException ("ch == null"); 1352 } else if (start < 0) { 1353 throw new IllegalArgumentException ("start (" + start + ") < 0"); 1354 } else if (start >= ch.length) { 1355 throw new IllegalArgumentException ("start (" + start + ") >= ch.length (" + ch.length + ')'); 1356 } else if (length < 0) { 1357 throw new IllegalArgumentException ("length < 0"); 1358 } 1359 1360 XMLEventListenerState oldState = _state; 1361 1362 _state = ERROR_STATE; 1365 1366 if (oldState == START_TAG_OPEN) { 1368 closeStartTag(); 1369 } 1370 1371 _encoder.whitespace(_out, ch, start, length); 1373 1374 if (oldState == BEFORE_XML_DECLARATION) { 1376 _state = BEFORE_DTD_DECLARATION; 1377 } else if (oldState == START_TAG_OPEN) { 1378 _state = WITHIN_ELEMENT; 1379 } else { 1380 _state = oldState; 1381 } 1382 1383 checkInvariants(); 1385 } 1386 1387 1417 public final void comment(String text) 1418 throws IllegalStateException , IllegalArgumentException , InvalidXMLException, IOException { 1419 1420 if (_state != BEFORE_XML_DECLARATION 1422 && _state != BEFORE_DTD_DECLARATION 1423 && _state != BEFORE_ROOT_ELEMENT 1424 && _state != START_TAG_OPEN 1425 && _state != WITHIN_ELEMENT 1426 && _state != AFTER_ROOT_ELEMENT) { 1427 throw new IllegalStateException ("getState() == " + _state); 1428 1429 } else if (text == null) { 1431 throw new IllegalArgumentException ("text == null"); 1432 } 1433 1434 XMLEventListenerState oldState = _state; 1435 1436 _state = ERROR_STATE; 1439 1440 if (oldState == START_TAG_OPEN) { 1442 _out.write('>'); 1443 _out.write('<'); 1444 _out.write('!'); 1445 _out.write('-'); 1446 _out.write('-'); 1447 } else { 1448 _out.write('<'); 1449 _out.write('!'); 1450 _out.write('-'); 1451 _out.write('-'); 1452 } 1453 _encoder.text(_out, text, _escapeAmpersands); 1454 _out.write('-'); 1455 _out.write('-'); 1456 _out.write('>'); 1457 1458 _out.write(_lineBreakChars); 1459 1460 if (oldState == BEFORE_XML_DECLARATION) { 1462 _state = BEFORE_DTD_DECLARATION; 1463 } else if (oldState == START_TAG_OPEN) { 1464 _state = WITHIN_ELEMENT; 1465 } else { 1466 _state = oldState; 1467 } 1468 1469 checkInvariants(); 1471 } 1472 1473 1509 public final void pi(String target, String instruction) 1510 throws IllegalStateException , IllegalArgumentException , IOException { 1511 1512 if (_state != BEFORE_XML_DECLARATION 1514 && _state != BEFORE_DTD_DECLARATION 1515 && _state != BEFORE_ROOT_ELEMENT 1516 && _state != START_TAG_OPEN 1517 && _state != WITHIN_ELEMENT 1518 && _state != AFTER_ROOT_ELEMENT) { 1519 throw new IllegalStateException ("getState() == " + _state); 1520 1521 } else if (target == null) { 1523 throw new IllegalArgumentException ("target == null"); 1524 } 1525 1526 XMLEventListenerState oldState = _state; 1527 1528 _state = ERROR_STATE; 1531 1532 if (oldState == START_TAG_OPEN) { 1534 closeStartTag(); 1535 } 1536 1537 _out.write('<'); 1539 _out.write('?'); 1540 _out.write(target); 1541 if (instruction != null) { 1542 _out.write(' '); 1543 _out.write(instruction); 1544 } 1545 _out.write('?'); 1546 _out.write('>'); 1547 1548 if (oldState == BEFORE_XML_DECLARATION) { 1550 _state = BEFORE_DTD_DECLARATION; 1551 } else if (oldState == START_TAG_OPEN) { 1552 _state = WITHIN_ELEMENT; 1553 } else { 1554 _state = oldState; 1555 } 1556 1557 checkInvariants(); 1559 } 1560 1561 1592 public final void cdata(String text) 1593 throws IllegalStateException , IllegalArgumentException , IOException { 1594 1595 if (_state != START_TAG_OPEN 1597 && _state != WITHIN_ELEMENT) { 1598 throw new IllegalStateException ("getState() == " + _state); 1599 1600 } else if (text == null) { 1602 throw new IllegalArgumentException ("text == null"); 1603 } 1604 1605 boolean startTagOpen = _state == START_TAG_OPEN; 1606 1607 _state = ERROR_STATE; 1610 1611 if (startTagOpen) { 1613 closeStartTag(); 1614 } 1615 1616 _out.write("<![CDATA["); 1617 _out.write(text); 1618 _out.write(']'); 1619 _out.write(']'); 1620 _out.write('>'); 1621 1622 _state = WITHIN_ELEMENT; 1624 1625 checkInvariants(); 1627 } 1628 1629 1645 public final void close() 1646 throws IllegalStateException , IOException { 1647 1648 if (_state != START_TAG_OPEN 1650 && _state != WITHIN_ELEMENT 1651 && _state != AFTER_ROOT_ELEMENT) { 1652 throw new IllegalStateException ("getState() == " + _state); 1653 } 1654 1655 while (_elementStackSize > 0) { 1656 endTag(); 1657 } 1658 1659 checkInvariants(); 1661 } 1662 1663 1680 public final void endDocument() 1681 throws IllegalStateException , IOException { 1682 1683 if (_state != START_TAG_OPEN && 1685 _state != WITHIN_ELEMENT && 1686 _state != AFTER_ROOT_ELEMENT) { 1687 throw new IllegalStateException ("getState() == " + _state); 1688 } 1689 1690 close(); 1692 1693 _out.flush(); 1695 1696 _state = DOCUMENT_ENDED; 1698 1699 checkInvariants(); 1701 } 1702} 1703 | Popular Tags |