1 9 package javolution.xml.stream; 10 11 import java.io.IOException ; 12 import java.io.OutputStream ; 13 import java.io.OutputStreamWriter ; 14 import java.io.UnsupportedEncodingException ; 15 import java.io.Writer ; 16 17 import javolution.context.ObjectFactory; 18 import javolution.io.UTF8StreamWriter; 19 import javolution.lang.Reusable; 20 import javolution.text.CharArray; 21 import javolution.text.TextBuilder; 22 import j2me.lang.CharSequence; 23 import j2me.lang.IllegalStateException; 24 import j2mex.realtime.MemoryArea; 25 26 33 public final class XMLStreamWriterImpl implements XMLStreamWriter, Reusable { 34 35 38 private static final int BUFFER_LENGTH = 2048; 39 40 43 private int _nesting = 0; 44 45 48 private TextBuilder[] _qNames = new TextBuilder[16]; 49 50 53 private boolean _isElementOpen; 54 55 58 private boolean _isEmptyElement; 59 60 63 private final char[] _buffer = new char[BUFFER_LENGTH]; 64 65 68 private final NamespacesImpl _namespaces = new NamespacesImpl(); 69 70 73 private int _index; 74 75 78 private boolean _isRepairingNamespaces; 79 80 83 private String _repairingPrefix = "ns"; 84 85 88 private String _indentation; 89 90 93 private int _indentationLevel; 94 95 98 private boolean _automaticEmptyElements; 99 100 103 private int _autoNSCount; 104 105 108 ObjectFactory _objectFactory; 109 110 114 117 private Writer _writer; 118 119 122 private String _encoding; 123 124 127 private final UTF8StreamWriter _utf8StreamWriter = new UTF8StreamWriter(); 128 129 132 public XMLStreamWriterImpl() { 133 for (int i = 0; i < _qNames.length;) { 134 _qNames[i++] = new TextBuilder(); 135 } 136 } 137 138 144 public void setOutput(OutputStream out) throws XMLStreamException { 145 _utf8StreamWriter.setOutput(out); 146 _encoding = "UTF-8"; 147 setOutput(_utf8StreamWriter); 148 } 149 150 158 public void setOutput(OutputStream out, String encoding) 159 throws XMLStreamException { 160 if (encoding.equals("UTF-8") || encoding.equals("utf-8") 161 || encoding.equals("ASCII")) { 162 setOutput(out); } 164 try { 165 _encoding = encoding; 166 setOutput(new OutputStreamWriter (out, encoding)); 167 } catch (UnsupportedEncodingException e) { 168 throw new XMLStreamException(e); 169 } 170 } 171 172 180 public void setOutput(Writer writer) throws XMLStreamException { 181 if (_writer != null) 182 throw new IllegalStateException ("Writer not closed or reset"); 183 _writer = writer; 184 } 185 186 193 public void setRepairingNamespaces(boolean isRepairingNamespaces) { 194 _isRepairingNamespaces = isRepairingNamespaces; 195 } 196 197 205 public void setRepairingPrefix(String repairingPrefix) { 206 _repairingPrefix = repairingPrefix; 207 } 208 209 216 public void setIndentation(String indentation) { 217 _indentation = indentation; 218 } 219 220 229 public void setAutomaticEmptyElements(boolean automaticEmptyElements) { 230 _automaticEmptyElements = automaticEmptyElements; 231 } 232 233 public void reset() { 235 _automaticEmptyElements = false; 236 _autoNSCount = 0; 237 _encoding = null; 238 _indentation = null; 239 _indentationLevel = 0; 240 _index = 0; 241 _isElementOpen = false; 242 _isEmptyElement = false; 243 _isRepairingNamespaces = false; 244 _namespaces.reset(); 245 _nesting = 0; 246 _objectFactory = null; 247 _repairingPrefix = "ns"; 248 _utf8StreamWriter.reset(); 249 _writer = null; 250 } 251 252 public void writeStartElement(CharSequence localName) 254 throws XMLStreamException { 255 if (localName == null) 256 throw new XMLStreamException("Local name cannot be null"); 257 writeNewElement(null, localName, null); 258 } 259 260 public void writeStartElement(CharSequence namespaceURI, 262 CharSequence localName) throws XMLStreamException { 263 if (localName == null) 264 throw new XMLStreamException("Local name cannot be null"); 265 if (namespaceURI == null) 266 throw new XMLStreamException("Namespace URI cannot be null"); 267 writeNewElement(null, localName, namespaceURI); 268 } 269 270 public void writeStartElement(CharSequence prefix, CharSequence localName, 272 CharSequence namespaceURI) throws XMLStreamException { 273 if (localName == null) 274 throw new XMLStreamException("Local name cannot be null"); 275 if (namespaceURI == null) 276 throw new XMLStreamException("Namespace URI cannot be null"); 277 if (prefix == null) 278 throw new XMLStreamException("Prefix cannot be null"); 279 writeNewElement(prefix, localName, namespaceURI); 280 } 281 282 public void writeEmptyElement(CharSequence localName) 284 throws XMLStreamException { 285 writeStartElement(localName); 286 _isEmptyElement = true; 287 } 288 289 public void writeEmptyElement(CharSequence namespaceURI, 291 CharSequence localName) throws XMLStreamException { 292 writeStartElement(namespaceURI, localName); 293 _isEmptyElement = true; 294 } 295 296 public void writeEmptyElement(CharSequence prefix, CharSequence localName, 298 CharSequence namespaceURI) throws XMLStreamException { 299 writeStartElement(prefix, localName, namespaceURI); 300 _isEmptyElement = true; 301 } 302 303 public void writeEndElement() throws XMLStreamException { 305 if (_isElementOpen) { if (_automaticEmptyElements) { 307 _isEmptyElement = true; closeOpenTag(); 309 return; 310 } 311 closeOpenTag(); 312 } 313 if ((_indentation != null) && (_indentationLevel != _nesting - 1)) { 314 write('\n'); 317 for (int i = 1; i < _nesting; i++) { 318 writeStr(_indentation); 319 } 320 } 321 322 write('<'); 323 write('/'); 324 writeTB(_qNames[_nesting--]); 325 write('>'); 326 _namespaces.pop(); 327 } 328 329 public void writeEndDocument() throws XMLStreamException { 331 if (_isElementOpen) 332 closeOpenTag(); 333 while (_nesting > 0) { writeEndElement(); 335 } 336 } 337 338 public void close() throws XMLStreamException { 340 if (_writer != null) { 341 if (_nesting != 0) { writeEndDocument(); 343 } 344 flush(); 345 } 346 if (_objectFactory != null) { 347 _objectFactory.recycle(this); } else { 349 reset(); } 351 } 352 353 public void flush() throws XMLStreamException { 355 flushBuffer(); 356 try { 357 _writer.flush(); 358 } catch (IOException e) { 359 throw new XMLStreamException(e); 360 } 361 } 362 363 public void writeAttribute(CharSequence localName, CharSequence value) 365 throws XMLStreamException { 366 if (localName == null) 367 throw new XMLStreamException("Local name cannot be null"); 368 if (value == null) 369 throw new XMLStreamException("Value cannot be null"); 370 writeAttributeOrNamespace(null, null, localName, value); 371 } 372 373 public void writeAttribute(CharSequence namespaceURI, 375 CharSequence localName, CharSequence value) 376 throws XMLStreamException { 377 if (localName == null) 378 throw new XMLStreamException("Local name cannot be null"); 379 if (value == null) 380 throw new XMLStreamException("Value cannot be null"); 381 if (namespaceURI == null) 382 throw new XMLStreamException("Namespace URI cannot be null"); 383 writeAttributeOrNamespace(null, namespaceURI, localName, value); 384 } 385 386 public void writeAttribute(CharSequence prefix, CharSequence namespaceURI, 388 CharSequence localName, CharSequence value) 389 throws XMLStreamException { 390 if (localName == null) 391 throw new XMLStreamException("Local name cannot be null"); 392 if (value == null) 393 throw new XMLStreamException("Value cannot be null"); 394 if (namespaceURI == null) 395 throw new XMLStreamException("Namespace URI cannot be null"); 396 if (prefix == null) 397 throw new XMLStreamException("Prefix cannot be null"); 398 writeAttributeOrNamespace(prefix, namespaceURI, localName, value); 399 } 400 401 public void writeNamespace(CharSequence prefix, CharSequence namespaceURI) 403 throws XMLStreamException { 404 if ((prefix == null) || (prefix.length() == 0) 405 || _namespaces._xmlns.equals(prefix)) { 406 prefix = _namespaces._defaultNsPrefix; 407 } 408 if (!_isElementOpen) throw new IllegalStateException ("No open start element"); 410 _namespaces.setPrefix(prefix, 411 (namespaceURI == null) ? _namespaces._nullNsURI : namespaceURI, 412 true); 413 } 414 415 public void writeDefaultNamespace(CharSequence namespaceURI) 417 throws XMLStreamException { 418 writeNamespace(_namespaces._defaultNsPrefix, namespaceURI); 419 } 420 421 public void writeComment(CharSequence data) throws XMLStreamException { 423 if (_isElementOpen) 424 closeOpenTag(); 425 writeStr("<!--"); 426 if (data != null) { write(data); 428 } 429 writeStr("-->"); 430 } 431 432 public void writeProcessingInstruction(CharSequence target) 434 throws XMLStreamException { 435 writeProcessingInstruction(target, _noChar); 436 } 437 438 private final CharArray _noChar = new CharArray(""); 439 440 public void writeProcessingInstruction(CharSequence target, 442 CharSequence data) throws XMLStreamException { 443 if (target == null) 444 throw new XMLStreamException("Target cannot be null"); 445 if (data == null) 446 throw new XMLStreamException("Data cannot be null"); 447 if (_isElementOpen) 448 closeOpenTag(); 449 writeStr("<?"); 450 write(target); 451 write(' '); 452 write(data); 453 write(" ?>"); 454 } 455 456 public void writeCData(CharSequence data) throws XMLStreamException { 458 if (data == null) 459 throw new XMLStreamException("Data cannot be null"); 460 if (_isElementOpen) 461 closeOpenTag(); 462 writeStr("<![CDATA["); 463 write(data); 464 writeStr("]]>"); 465 } 466 467 public void writeDTD(CharSequence dtd) throws XMLStreamException { 469 if (dtd == null) 470 throw new XMLStreamException("DTD cannot be null"); 471 if (_nesting > 0) 472 throw new XMLStreamException( 473 "DOCTYPE declaration (DTD) when not in document root (prolog)"); 474 write(dtd); 475 } 476 477 public void writeEntityRef(CharSequence name) throws XMLStreamException { 479 write('&'); 480 write(name); 481 write(';'); 482 } 483 484 public void writeStartDocument() throws XMLStreamException { 486 writeStartDocument(null, null); 487 } 488 489 public void writeStartDocument(CharSequence version) 491 throws XMLStreamException { 492 writeStartDocument(null, version); 493 } 494 495 public void writeStartDocument(CharSequence encoding, CharSequence version) 497 throws XMLStreamException { 498 if (_nesting > 0) 499 throw new XMLStreamException("Not in document root"); 500 writeStr("<?xml version=\""); 501 if (version != null) { 502 write(version); 503 write('"'); 504 } else { writeStr("1.0\""); 506 } 507 if (encoding != null) { 508 writeStr(" encoding=\""); 509 write(encoding); 510 write('"'); 511 } else if (_encoding != null) { writeStr(" encoding=\""); 513 writeStr(_encoding); 514 write('"'); 515 } 516 writeStr(" ?>"); 517 } 518 519 public void writeCharacters(CharSequence text) throws XMLStreamException { 521 if (_isElementOpen) 522 closeOpenTag(); 523 if (text == null) 524 return; 525 writeEsc(text); 526 } 527 528 public void writeCharacters(char[] text, int start, int length) 530 throws XMLStreamException { 531 for (int i = start, end = start + length; i < end;) { 532 writeEsc(text[i++]); 533 } 534 } 535 536 public CharSequence getPrefix(CharSequence uri) throws XMLStreamException { 538 return _namespaces.getPrefix(uri); 539 } 540 541 public void setPrefix(CharSequence prefix, CharSequence uri) 543 throws XMLStreamException { 544 _namespaces.setPrefix(prefix, (uri == null) ? _namespaces._nullNsURI 545 : uri, false); 546 } 547 548 public void setDefaultNamespace(CharSequence uri) throws XMLStreamException { 550 setPrefix(_namespaces._defaultNsPrefix, uri); 551 } 552 553 public Object getProperty(String name) throws IllegalArgumentException { 555 if (name.equals(XMLOutputFactory.IS_REPAIRING_NAMESPACES)) { 556 return new Boolean (_isRepairingNamespaces); 557 } else if (name.equals(XMLOutputFactory.REPAIRING_PREFIX)) { 558 return _repairingPrefix; 559 } else if (name.equals(XMLOutputFactory.AUTOMATIC_EMPTY_ELEMENTS)) { 560 return new Boolean (_automaticEmptyElements); 561 } else if (name.equals(XMLOutputFactory.INDENTATION)) { 562 return _indentation; 563 } else { 564 throw new IllegalArgumentException ("Property: " + name 565 + " not supported"); 566 } 567 } 568 569 private void writeNewElement(CharSequence prefix, CharSequence localName, 571 CharSequence namespaceURI) throws XMLStreamException { 572 573 if (_isElementOpen) 575 closeOpenTag(); 576 if (_indentation != null) { 577 write('\n'); 578 _indentationLevel = _nesting; 579 for (int i = 0; i < _indentationLevel; i++) { 580 writeStr(_indentation); 581 } 582 } 583 write('<'); 584 _isElementOpen = true; 585 586 if (++_nesting >= _qNames.length) 588 resizeElemStack(); 589 _namespaces.push(); 590 591 TextBuilder qName = _qNames[_nesting].clear(); 593 594 if ((namespaceURI != null) 596 && (!_namespaces._defaultNamespace.equals(namespaceURI))) { 597 if (_isRepairingNamespaces) { prefix = getRepairedPrefix(prefix, namespaceURI); 599 } else if (prefix == null) { prefix = getPrefix(namespaceURI); 601 if (prefix == null) 602 throw new XMLStreamException("URI: " + namespaceURI 603 + " not bound and repairing namespaces disabled"); 604 } 605 if (prefix.length() > 0) { 606 qName.append(prefix); 607 qName.append(':'); 608 } 609 } 610 qName.append(localName); 611 writeTB(qName); 612 } 613 614 private void writeAttributeOrNamespace(CharSequence prefix, 616 CharSequence namespaceURI, CharSequence localName, 617 CharSequence value) throws XMLStreamException { 618 if (!_isElementOpen) 619 throw new IllegalStateException ("No open start element"); 620 write(' '); 621 622 if ((namespaceURI != null) 624 && (!_namespaces._defaultNamespace.equals(namespaceURI))) { 625 if (_isRepairingNamespaces) { prefix = getRepairedPrefix(prefix, namespaceURI); 627 } else if (prefix == null) { 628 prefix = getPrefix(namespaceURI); 629 if (prefix == null) 630 throw new XMLStreamException("URI: " + namespaceURI 631 + " not bound and repairing namespaces disabled"); 632 } 633 if (prefix.length() > 0) { 634 write(prefix); 635 write(':'); 636 } 637 } 638 639 write(localName); 640 write('='); 641 write('"'); 642 writeEsc(value); 643 write('"'); 644 } 645 646 private void closeOpenTag() throws XMLStreamException { 648 649 writeNamespaces(); 651 652 _isElementOpen = false; 654 if (_isEmptyElement) { 655 write('/'); 656 write('>'); 657 _nesting--; 658 _namespaces.pop(); 659 _isEmptyElement = false; 660 } else { 661 write('>'); 662 } 663 } 664 665 private void writeNamespaces() throws XMLStreamException { 668 int i0 = (_nesting > 1) ? _namespaces._namespacesCount[_nesting - 2] 669 : NamespacesImpl.NBR_PREDEFINED_NAMESPACES; 670 int i1 = _namespaces._namespacesCount[_nesting - 1]; 671 int i2 = _namespaces._namespacesCount[_nesting]; 672 for (int i = i0; i < i2; i++) { 673 if (((_isRepairingNamespaces && (i < i1) && !_namespaces._prefixesWritten[i])) 674 || ((i >= i1) && _namespaces._prefixesWritten[i])) { 676 if (_isRepairingNamespaces) { 678 CharArray prefix = _namespaces.getPrefix( 679 _namespaces._namespaces[i], i); 680 if (_namespaces._prefixes[i].equals(prefix)) 681 continue; } 684 if (_namespaces._prefixes[i].length() == 0) { writeAttributeOrNamespace(null, null, _namespaces._xmlns, 687 _namespaces._namespaces[i]); 688 } else { 689 writeAttributeOrNamespace(_namespaces._xmlns, 690 _namespaces._xmlnsURI, _namespaces._prefixes[i], 691 _namespaces._namespaces[i]); 692 } 693 } 694 } 695 } 696 697 private CharSequence getRepairedPrefix(CharSequence prefix, 699 CharSequence namespaceURI) throws XMLStreamException { 700 CharArray prefixForURI = _namespaces.getPrefix(namespaceURI); 701 if ((prefixForURI != null) 702 && ((prefix == null) || prefixForURI.equals(prefix))) 703 return prefixForURI; if ((prefix == null) || (prefix.length() == 0)) { prefix = _autoPrefix.clear().append(_repairingPrefix).append( 706 _autoNSCount++); 707 } 708 _namespaces.setPrefix(prefix, namespaceURI, true); return prefix; 710 } 711 712 private final TextBuilder _autoPrefix = new TextBuilder(); 713 714 private void resizeElemStack() { 716 MemoryArea.getMemoryArea(this).executeInArea(new Runnable () { 717 public void run() { 718 final int oldLength = _qNames.length; 719 final int newLength = oldLength * 2; 720 721 TextBuilder[] tmp = new TextBuilder[newLength]; 723 System.arraycopy(_qNames, 0, tmp, 0, oldLength); 724 _qNames = tmp; 725 for (int i = oldLength; i < newLength; i++) { 726 _qNames[i] = new TextBuilder(); 727 } 728 } 729 }); 730 } 731 732 735 private final void write(char c) throws XMLStreamException { 736 _buffer[_index++] = c; 737 if (_index == BUFFER_LENGTH) { 738 flushBuffer(); 739 } 740 } 741 742 private final void writeEsc(char c) throws XMLStreamException { 743 if ((c >= '?') 744 || ((c >= ' ') && (c != '<') && (c != '>') && (c != '"') && (c != '&'))) { write(c); 746 } else { 747 writeEsc2(c); 748 } 749 } 750 751 private final void writeEsc2(char c) throws XMLStreamException { 752 switch (c) { 753 case '<': 754 writeStr("<"); 755 break; 756 case '>': 757 writeStr(">"); 758 break; 759 case '"': 763 writeStr("""); 764 break; 765 case '&': 766 writeStr("&"); 767 break; 768 default: 769 if (c >= ' ') { 770 write(c); 771 } else { 772 writeStr("&#"); 773 write((char) ('0' + c / 10)); 774 write((char) ('0' + c % 10)); 775 write(';'); 776 } 777 } 778 } 779 780 private void write(Object obj) throws XMLStreamException { 781 if (obj instanceof String ) { 782 writeStr((String ) obj); 783 } else { 784 writeCsq((CharSequence ) obj); 785 } 786 } 787 788 private void writeStr(String str) throws XMLStreamException { 789 int n = str.length(); 790 if (_index + n < BUFFER_LENGTH) { 791 str.getChars(0, n, _buffer, _index); 792 _index += n; 793 } else { 794 writeStrImmediate(str); 795 } 796 } 797 798 private void writeStrImmediate(String str) throws XMLStreamException { 799 flushBuffer(); 800 try { 801 _writer.write(str); 802 } catch (IOException e) { 803 throw new XMLStreamException(e); 804 } 805 } 806 807 private void writeCsq(CharSequence csq) throws XMLStreamException { 808 for (int i = 0, n = csq.length(); i < n;) { 809 _buffer[_index++] = csq.charAt(i++); 811 if (_index == BUFFER_LENGTH) { 812 flushBuffer(); 813 } 814 } 815 } 816 817 private void writeTB(TextBuilder tb) throws XMLStreamException { 818 for (int i = 0, n = tb.length(); i < n;) { 819 _buffer[_index++] = tb.charAt(i++); 821 if (_index == BUFFER_LENGTH) { 822 flushBuffer(); 823 } 824 } 825 } 826 827 private void writeEsc(Object obj) throws XMLStreamException { 828 if (obj instanceof String ) { 829 writeEscStr((String ) obj); 830 } else { 831 writeEscCsq((CharSequence ) obj); 832 } 833 } 834 835 private void writeEscStr(String str) throws XMLStreamException { 836 for (int i = 0, n = str.length(); i < n;) { 837 char c = str.charAt(i++); 839 if ((c >= '?') 840 || ((c >= ' ') && (c != '<') && (c != '>') && (c != '"') && (c != '&'))) { _buffer[_index++] = c; 843 if (_index == BUFFER_LENGTH) { 844 flushBuffer(); 845 } 846 } else { 847 writeEsc2(c); 848 } 849 } 850 } 851 852 private void writeEscCsq(CharSequence csq) throws XMLStreamException { 853 for (int i = 0, n = csq.length(); i < n;) { 854 char c = csq.charAt(i++); 856 if ((c >= '?') 857 || ((c >= ' ') && (c != '<') && (c != '>') && (c != '"') && (c != '&'))) { _buffer[_index++] = c; 860 if (_index == BUFFER_LENGTH) { 861 flushBuffer(); 862 } 863 } else { 864 writeEsc2(c); 865 } 866 } 867 } 868 869 private void flushBuffer() throws XMLStreamException { 870 try { 871 _writer.write(_buffer, 0, _index); 872 } catch (IOException e) { 873 throw new XMLStreamException(e); 874 } finally { 875 _index = 0; 876 } 877 } 878 879 } | Popular Tags |