| 1 57 58 59 83 84 package org.enhydra.apache.xml.serialize; 85 86 87 import java.io.IOException ; 88 import java.io.OutputStream ; 89 import java.io.Writer ; 90 import java.util.Hashtable ; 91 import java.util.Vector ; 92 93 import org.w3c.dom.DOMImplementation ; 94 import org.w3c.dom.Document ; 95 import org.w3c.dom.DocumentFragment ; 96 import org.w3c.dom.DocumentType ; 97 import org.w3c.dom.Element ; 98 import org.w3c.dom.Entity ; 99 import org.w3c.dom.NamedNodeMap ; 100 import org.w3c.dom.Node ; 101 import org.w3c.dom.Notation ; 102 import org.xml.sax.ContentHandler ; 103 import org.xml.sax.DTDHandler ; 104 import org.xml.sax.DocumentHandler ; 105 import org.xml.sax.Locator ; 106 import org.xml.sax.SAXException ; 107 import org.xml.sax.ext.DeclHandler ; 108 import org.xml.sax.ext.LexicalHandler ; 109 110 111 155 public abstract class BaseMarkupSerializer 156 implements ContentHandler , DocumentHandler , LexicalHandler , 157 DTDHandler , DeclHandler , DOMSerializer, Serializer 158 { 159 160 161 private EncodingInfo _encodingInfo; 162 163 164 170 private ElementState[] _elementStates; 171 172 173 178 private int _elementStateCount; 179 180 181 185 private Vector _preRoot; 186 187 188 192 protected boolean _started; 193 194 195 200 private boolean _prepared; 201 202 203 208 protected Hashtable _prefixes; 209 210 211 214 protected String _docTypePublicId; 215 216 217 220 protected String _docTypeSystemId; 221 222 223 229 protected OutputFormat _format; 230 231 232 235 protected Printer _printer; 236 237 238 241 protected boolean _indenting; 242 243 244 247 private Writer _writer; 248 249 250 253 private OutputStream _output; 254 255 256 260 261 266 protected BaseMarkupSerializer( OutputFormat format ) 267 { 268 int i; 269 270 _elementStates = new ElementState[ 10 ]; 271 for ( i = 0 ; i < _elementStates.length ; ++i ) 272 _elementStates[ i ] = new ElementState(); 273 _format = format; 274 } 275 276 277 public DocumentHandler asDocumentHandler() 278 throws IOException  279 { 280 prepare(); 281 return this; 282 } 283 284 285 public ContentHandler asContentHandler() 286 throws IOException  287 { 288 prepare(); 289 return this; 290 } 291 292 293 public DOMSerializer asDOMSerializer() 294 throws IOException  295 { 296 prepare(); 297 return this; 298 } 299 300 301 public void setOutputByteStream( OutputStream output ) 302 { 303 if ( output == null ) 304 throw new NullPointerException ( "SER001 Argument 'output' is null." ); 305 _output = output; 306 _writer = null; 307 reset(); 308 } 309 310 311 public void setOutputCharStream( Writer writer ) 312 { 313 if ( writer == null ) 314 throw new NullPointerException ( "SER001 Argument 'writer' is null." ); 315 _writer = writer; 316 _output = null; 317 reset(); 318 } 319 320 321 public void setOutputFormat( OutputFormat format ) 322 { 323 if ( format == null ) 324 throw new NullPointerException ( "SER001 Argument 'format' is null." ); 325 _format = format; 326 reset(); 327 } 328 329 330 public boolean reset() 331 { 332 if ( _elementStateCount > 1 ) 333 throw new IllegalStateException ( "Serializer reset in the middle of serialization" ); 334 _prepared = false; 335 return true; 336 } 337 338 339 protected void prepare() 340 throws IOException  341 { 342 if ( _prepared ) 343 return; 344 345 if ( _writer == null && _output == null ) 346 throw new IOException ( "SER002 No writer supplied for serializer" ); 347 351 _encodingInfo = _format.getEncodingInfo(); 352 353 if ( _output != null ) { 354 _writer = _encodingInfo.getWriter(_output); 355 } 356 357 if ( _format.getIndenting() ) { 358 _indenting = true; 359 _printer = new IndentPrinter( _writer, _format ); 360 } else { 361 _indenting = false; 362 _printer = new Printer( _writer, _format ); 363 } 364 365 ElementState state; 366 367 _elementStateCount = 0; 368 state = _elementStates[ 0 ]; 369 state.namespaceURI = null; 370 state.localName = null; 371 state.rawName = null; 372 state.preserveSpace = _format.getPreserveSpace(); 373 state.empty = true; 374 state.afterElement = false; 375 state.afterComment = false; 376 state.doCData = state.inCData = false; 377 state.prefixes = null; 378 379 _docTypePublicId = _format.getDoctypePublic(); 380 _docTypeSystemId = _format.getDoctypeSystem(); 381 _started = false; 382 _prepared = true; 383 } 384 385 386 387 391 392 401 public void serialize( Element elem ) 402 throws IOException  403 { 404 prepare(); 405 serializeNode( elem ); 406 _printer.flush(); 407 if ( _printer.getException() != null ) 408 throw _printer.getException(); 409 } 410 411 412 421 public void serialize( DocumentFragment frag ) 422 throws IOException  423 { 424 prepare(); 425 serializeNode( frag ); 426 _printer.flush(); 427 if ( _printer.getException() != null ) 428 throw _printer.getException(); 429 } 430 431 432 441 public void serialize( Document doc ) 442 throws IOException  443 { 444 prepare(); 445 serializeNode( doc ); 446 serializePreRoot(); 447 _printer.flush(); 448 if ( _printer.getException() != null ) 449 throw _printer.getException(); 450 } 451 452 453 457 458 public void startDocument() 459 throws SAXException  460 { 461 try { 462 prepare(); 463 } catch ( IOException except ) { 464 throw new SAXException ( except.toString() ); 465 } 466 } 468 469 470 public void characters( char[] chars, int start, int length ) 471 throws SAXException  472 { 473 ElementState state; 474 475 try { 476 state = content(); 477 478 482 if ( state.inCData || state.doCData ) { 483 int saveIndent; 484 485 if ( ! state.inCData ) { 489 _printer.printText( "<![CDATA[" ); 490 state.inCData = true; 491 } 492 saveIndent = _printer.getNextIndent(); 493 _printer.setNextIndent( 0 ); 494 for ( int index = 0 ; index < length ; ++index ) { 495 if ( index + 2 < length && chars[ index ] == ']' && 496 chars[ index + 1 ] == ']' && chars[ index + 2 ] == '>' ) { 497 498 printText( chars, start, index + 2, true, true ); 499 _printer.printText( "]]><![CDATA[" ); 500 start += index + 2; 501 length -= index + 2; 502 index = 0; 503 } 504 } 505 if ( length > 0 ) 506 printText( chars, start, length, true, true ); 507 _printer.setNextIndent( saveIndent ); 508 509 } else { 510 511 int saveIndent; 512 513 if ( state.preserveSpace ) { 514 saveIndent = _printer.getNextIndent(); 519 _printer.setNextIndent( 0 ); 520 printText( chars, start, length, true, state.unescaped ); 521 _printer.setNextIndent( saveIndent ); 522 } else { 523 printText( chars, start, length, false, state.unescaped ); 524 } 525 } 526 } catch ( IOException except ) { 527 throw new SAXException ( except ); 528 } 529 } 530 531 532 public void ignorableWhitespace( char[] chars, int start, int length ) 533 throws SAXException  534 { 535 int i; 536 537 try { 538 content(); 539 540 if ( _indenting ) { 544 _printer.setThisIndent( 0 ); 545 for ( i = start ; length-- > 0 ; ++i ) 546 _printer.printText( chars[ i ] ); 547 } 548 } catch ( IOException except ) { 549 throw new SAXException ( except ); 550 } 551 } 552 553 554 public final void processingInstruction( String target, String code ) 555 throws SAXException  556 { 557 try { 558 processingInstructionIO( target, code ); 559 } catch ( IOException except ) { 560 throw new SAXException ( except ); 561 } 562 } 563 564 public void processingInstructionIO( String target, String code ) 565 throws IOException  566 { 567 int index; 568 StringBuffer buffer; 569 ElementState state; 570 571 state = content(); 572 buffer = new StringBuffer ( 40 ); 573 574 index = target.indexOf( "?>" ); 577 if ( index >= 0 ) 578 buffer.append( "<?" ).append( target.substring( 0, index ) ); 579 else 580 buffer.append( "<?" ).append( target ); 581 if ( code != null ) { 582 buffer.append( ' ' ); 583 index = code.indexOf( "?>" ); 584 if ( index >= 0 ) 585 buffer.append( code.substring( 0, index ) ); 586 else 587 buffer.append( code ); 588 } 589 buffer.append( "?>" ); 590 591 if ( isDocumentState() ) { 594 if ( _preRoot == null ) 595 _preRoot = new Vector (); 596 _preRoot.addElement( buffer.toString() ); 597 } else { 598 _printer.indent(); 599 printText( buffer.toString(), true, true ); 600 _printer.unindent(); 601 if ( _indenting ) 602 state.afterElement = true; 603 } 604 } 605 606 607 public void comment( char[] chars, int start, int length ) 608 throws SAXException  609 { 610 try { 611 comment( new String ( chars, start, length ) ); 612 } catch ( IOException except ) { 613 throw new SAXException ( except ); 614 } 615 } 616 617 618 public void comment( String text ) 619 throws IOException  620 { 621 StringBuffer buffer; 622 int index; 623 ElementState state; 624 625 if ( _format.getOmitComments() ) 626 return; 627 628 state = content(); 629 buffer = new StringBuffer ( 40 ); 630 index = text.indexOf( "-->" ); 633 if ( index >= 0 ) 634 buffer.append( "<!--" ).append( text.substring( 0, index ) ).append( "-->" ); 635 else 636 buffer.append( "<!--" ).append( text ).append( "-->" ); 637 638 if ( isDocumentState() ) { 641 if ( _preRoot == null ) 642 _preRoot = new Vector (); 643 _preRoot.addElement( buffer.toString() ); 644 } else { 645 if ( _indenting && ! state.preserveSpace) 649 _printer.breakLine(); 650 _printer.indent(); 651 printText( buffer.toString(), true, true ); 652 _printer.unindent(); 653 if ( _indenting ) 654 state.afterElement = true; 655 } 656 state.afterComment = true; 657 state.afterElement = false; 658 } 659 660 661 public void startCDATA() 662 { 663 ElementState state; 664 665 state = getElementState(); 666 state.doCData = true; 667 } 668 669 670 public void endCDATA() 671 { 672 ElementState state; 673 674 state = getElementState(); 675 state.doCData = false; 676 } 677 678 679 public void startNonEscaping() 680 { 681 ElementState state; 682 683 state = getElementState(); 684 state.unescaped = true; 685 } 686 687 688 public void endNonEscaping() 689 { 690 ElementState state; 691 692 state = getElementState(); 693 state.unescaped = false; 694 } 695 696 697 public void startPreserving() 698 { 699 ElementState state; 700 701 state = getElementState(); 702 state.preserveSpace = true; 703 } 704 705 706 public void endPreserving() 707 { 708 ElementState state; 709 710 state = getElementState(); 711 state.preserveSpace = false; 712 } 713 714 715 723 public void endDocument() 724 throws SAXException  725 { 726 try { 727 serializePreRoot(); 730 _printer.flush(); 732 } catch ( IOException except ) { 733 throw new SAXException ( except ); 734 } 735 } 736 737 738 public void startEntity( String name ) 739 { 740 } 742 743 744 public void endEntity( String name ) 745 { 746 } 748 749 750 public void setDocumentLocator( Locator locator ) 751 { 752 } 754 755 756 760 761 public void skippedEntity ( String name ) 762 throws SAXException  763 { 764 try { 765 endCDATA(); 766 content(); 767 _printer.printText( '&' ); 768 _printer.printText( name ); 769 _printer.printText( ';' ); 770 } catch ( IOException except ) { 771 throw new SAXException ( except ); 772 } 773 } 774 775 776 public void startPrefixMapping( String prefix, String uri ) 777 throws SAXException  778 { 779 if ( _prefixes == null ) 780 _prefixes = new Hashtable (); 781 _prefixes.put( uri, prefix == null ? "" : prefix ); 782 } 783 784 785 public void endPrefixMapping( String prefix ) 786 throws SAXException  787 { 788 } 789 790 791 795 796 public final void startDTD( String name, String publicId, String systemId ) 797 throws SAXException  798 { 799 try { 800 _printer.enterDTD(); 801 _docTypePublicId = publicId; 802 _docTypeSystemId = systemId; 803 } catch ( IOException except ) { 804 throw new SAXException ( except ); 805 } 806 } 807 808 809 public void endDTD() 810 { 811 } 813 814 815 public void elementDecl( String name, String model ) 816 throws SAXException  817 { 818 try { 819 _printer.enterDTD(); 820 _printer.printText( "<!ELEMENT " ); 821 _printer.printText( name ); 822 _printer.printText( ' ' ); 823 _printer.printText( model ); 824 _printer.printText( '>' ); 825 if ( _indenting ) 826 _printer.breakLine(); 827 } catch ( IOException except ) { 828 throw new SAXException ( except ); 829 } 830 } 831 832 833 public void attributeDecl( String eName, String aName, String type, 834 String valueDefault, String value ) 835 throws SAXException  836 { 837 try { 838 _printer.enterDTD(); 839 _printer.printText( "<!ATTLIST " ); 840 _printer.printText( eName ); 841 _printer.printText( ' ' ); 842 _printer.printText( aName ); 843 _printer.printText( ' ' ); 844 _printer.printText( type ); 845 if ( valueDefault != null ) { 846 _printer.printText( ' ' ); 847 _printer.printText( valueDefault ); 848 } 849 if ( value != null ) { 850 _printer.printText( " \"" ); 851 printEscaped( value ); 852 _printer.printText( '"' ); 853 } 854 _printer.printText( '>' ); 855 if ( _indenting ) 856 _printer.breakLine(); 857 } catch ( IOException except ) { 858 throw new SAXException ( except ); 859 } 860 } 861 862 863 public void internalEntityDecl( String name, String value ) 864 throws SAXException  865 { 866 try { 867 _printer.enterDTD(); 868 _printer.printText( "<!ENTITY " ); 869 _printer.printText( name ); 870 _printer.printText( " \"" ); 871 printEscaped( value ); 872 _printer.printText( "\">" ); 873 if ( _indenting ) 874 _printer.breakLine(); 875 } catch ( IOException except ) { 876 throw new SAXException ( except ); 877 } 878 } 879 880 881 public void externalEntityDecl( String name, String publicId, String systemId ) 882 throws SAXException  883 { 884 try { 885 _printer.enterDTD(); 886 unparsedEntityDecl( name, publicId, systemId, null ); 887 } catch ( IOException except ) { 888 throw new SAXException ( except ); 889 } 890 } 891 892 893 public void unparsedEntityDecl( String name, String publicId, 894 String systemId, String notationName ) 895 throws SAXException  896 { 897 try { 898 _printer.enterDTD(); 899 if ( publicId == null ) { 900 _printer.printText( "<!ENTITY " ); 901 _printer.printText( name ); 902 _printer.printText( " SYSTEM " ); 903 printDoctypeURL( systemId ); 904 &nbs
|