1 57 58 59 73 74 package com.sun.org.apache.xml.internal.serialize; 75 76 import com.sun.org.apache.xerces.internal.dom.DOMMessageFormatter; 77 78 import java.io.IOException ; 79 import java.io.OutputStream ; 80 import java.io.Writer ; 81 import java.util.Enumeration ; 82 import java.util.Locale ; 83 84 import org.w3c.dom.Attr ; 85 import org.w3c.dom.Element ; 86 import org.w3c.dom.NamedNodeMap ; 87 import org.w3c.dom.Node ; 88 import org.xml.sax.AttributeList ; 89 import org.xml.sax.Attributes ; 90 import org.xml.sax.SAXException ; 91 92 93 131 public class HTMLSerializer 132 extends BaseMarkupSerializer 133 { 134 135 136 139 private boolean _xhtml; 140 141 142 public static final String XHTMLNamespace = "http://www.w3.org/1999/xhtml"; 143 144 private String fUserXHTMLNamespace = null; 146 147 148 155 protected HTMLSerializer( boolean xhtml, OutputFormat format ) 156 { 157 super( format ); 158 _xhtml = xhtml; 159 } 160 161 162 167 public HTMLSerializer() 168 { 169 this( false, new OutputFormat( Method.HTML, "ISO-8859-1", false ) ); 170 } 171 172 173 178 public HTMLSerializer( OutputFormat format ) 179 { 180 this( false, format != null ? format : new OutputFormat( Method.HTML, "ISO-8859-1", false ) ); 181 } 182 183 184 185 193 public HTMLSerializer( Writer writer, OutputFormat format ) 194 { 195 this( false, format != null ? format : new OutputFormat( Method.HTML, "ISO-8859-1", false ) ); 196 setOutputCharStream( writer ); 197 } 198 199 200 208 public HTMLSerializer( OutputStream output, OutputFormat format ) 209 { 210 this( false, format != null ? format : new OutputFormat( Method.HTML, "ISO-8859-1", false ) ); 211 setOutputByteStream( output ); 212 } 213 214 215 public void setOutputFormat( OutputFormat format ) 216 { 217 super.setOutputFormat( format != null ? format : new OutputFormat( Method.HTML, "ISO-8859-1", false ) ); 218 } 219 220 public void setXHTMLNamespace(String newNamespace) { 222 fUserXHTMLNamespace = newNamespace; 223 } 225 229 230 public void startElement( String namespaceURI, String localName, 231 String rawName, Attributes attrs ) 232 throws SAXException 233 { 234 int i; 235 boolean preserveSpace; 236 ElementState state; 237 String name; 238 String value; 239 String htmlName; 240 boolean addNSAttr = false; 241 242 try { 243 if ( _printer == null ) 244 throw new IllegalStateException ( 245 DOMMessageFormatter.formatMessage( 246 DOMMessageFormatter.SERIALIZER_DOMAIN, 247 "NoWriterSupplied", null)); 248 249 state = getElementState(); 250 if ( isDocumentState() ) { 251 if ( ! _started ) 256 startDocument( (localName == null || localName.length() == 0) 257 ? rawName : localName ); 258 } else { 259 if ( state.empty ) 263 _printer.printText( '>' ); 264 if ( _indenting && ! state.preserveSpace && 268 ( state.empty || state.afterElement ) ) 269 _printer.breakLine(); 270 } 271 preserveSpace = state.preserveSpace; 272 273 276 boolean hasNamespaceURI = (namespaceURI != null && namespaceURI.length() != 0); 280 281 if ( rawName == null || rawName.length() == 0) { 284 rawName = localName; 285 if ( hasNamespaceURI ) { 286 String prefix; 287 prefix = getPrefix( namespaceURI ); 288 if ( prefix != null && prefix.length() != 0 ) 289 rawName = prefix + ":" + localName; 290 } 291 addNSAttr = true; 292 } 293 if ( !hasNamespaceURI ) 294 htmlName = rawName; 295 else { 296 if ( namespaceURI.equals( XHTMLNamespace ) || 297 (fUserXHTMLNamespace != null && fUserXHTMLNamespace.equals(namespaceURI)) ) 298 htmlName = localName; 299 else 300 htmlName = null; 301 } 302 303 _printer.printText( '<' ); 305 if ( _xhtml ) 306 _printer.printText( rawName.toLowerCase(Locale.ENGLISH) ); 307 else 308 _printer.printText( rawName ); 309 _printer.indent(); 310 311 if ( attrs != null ) { 315 for ( i = 0 ; i < attrs.getLength() ; ++i ) { 316 _printer.printSpace(); 317 name = attrs.getQName( i ).toLowerCase(Locale.ENGLISH); 318 value = attrs.getValue( i ); 319 if ( _xhtml || hasNamespaceURI ) { 320 if ( value == null ) { 322 _printer.printText( name ); 323 _printer.printText( "=\"\"" ); 324 } else { 325 _printer.printText( name ); 326 _printer.printText( "=\"" ); 327 printEscaped( value ); 328 _printer.printText( '"' ); 329 } 330 } else { 331 if ( value == null ) { 334 value = ""; 335 } 336 if ( !_format.getPreserveEmptyAttributes() && value.length() == 0 ) 337 _printer.printText( name ); 338 else if ( HTMLdtd.isURI( rawName, name ) ) { 339 _printer.printText( name ); 340 _printer.printText( "=\"" ); 341 _printer.printText( escapeURI( value ) ); 342 _printer.printText( '"' ); 343 } else if ( HTMLdtd.isBoolean( rawName, name ) ) 344 _printer.printText( name ); 345 else { 346 _printer.printText( name ); 347 _printer.printText( "=\"" ); 348 printEscaped( value ); 349 _printer.printText( '"' ); 350 } 351 } 352 } 353 } 354 if ( htmlName != null && HTMLdtd.isPreserveSpace( htmlName ) ) 355 preserveSpace = true; 356 357 if ( addNSAttr ) { 358 Enumeration keys; 359 360 keys = _prefixes.keys(); 361 while ( keys.hasMoreElements() ) { 362 _printer.printSpace(); 363 value = (String ) keys.nextElement(); 364 name = (String ) _prefixes.get( value ); 365 if ( name.length() == 0 ) { 366 _printer.printText( "xmlns=\"" ); 367 printEscaped( value ); 368 _printer.printText( '"' ); 369 } else { 370 _printer.printText( "xmlns:" ); 371 _printer.printText( name ); 372 _printer.printText( "=\"" ); 373 printEscaped( value ); 374 _printer.printText( '"' ); 375 } 376 } 377 } 378 379 state = enterElementState( namespaceURI, localName, rawName, preserveSpace ); 383 384 386 if ( htmlName != null && ( htmlName.equalsIgnoreCase( "A" ) || 387 htmlName.equalsIgnoreCase( "TD" ) ) ) { 388 state.empty = false; 389 _printer.printText( '>' ); 390 } 391 392 if ( htmlName != null && ( rawName.equalsIgnoreCase( "SCRIPT" ) || 396 rawName.equalsIgnoreCase( "STYLE" ) ) ) { 397 if ( _xhtml ) { 398 state.doCData = true; 400 } else { 401 state.unescaped = true; 403 } 404 } 405 } catch ( IOException except ) { 406 throw new SAXException ( except ); 407 } 408 } 409 410 411 public void endElement( String namespaceURI, String localName, 412 String rawName ) 413 throws SAXException 414 { 415 try { 416 endElementIO( namespaceURI, localName, rawName ); 417 } catch ( IOException except ) { 418 throw new SAXException ( except ); 419 } 420 } 421 422 423 public void endElementIO( String namespaceURI, String localName, 424 String rawName ) 425 throws IOException 426 { 427 ElementState state; 428 String htmlName; 429 430 _printer.unindent(); 434 state = getElementState(); 435 436 if ( state.namespaceURI == null || state.namespaceURI.length() == 0 ) 437 htmlName = state.rawName; 438 else { 439 if ( state.namespaceURI.equals( XHTMLNamespace ) || 440 (fUserXHTMLNamespace != null && fUserXHTMLNamespace.equals(state.namespaceURI)) ) 441 htmlName = state.localName; 442 else 443 htmlName = null; 444 } 445 446 if ( _xhtml) { 447 if ( state.empty ) { 448 _printer.printText( " />" ); 449 } else { 450 if ( state.inCData ) 452 _printer.printText( "]]>" ); 453 _printer.printText( "</" ); 455 _printer.printText( state.rawName.toLowerCase(Locale.ENGLISH) ); 456 _printer.printText( '>' ); 457 } 458 } else { 459 if ( state.empty ) 460 _printer.printText( '>' ); 461 if ( htmlName == null || ! HTMLdtd.isOnlyOpening( htmlName ) ) { 467 if ( _indenting && ! state.preserveSpace && state.afterElement ) 468 _printer.breakLine(); 469 if ( state.inCData ) 471 _printer.printText( "]]>" ); 472 _printer.printText( "</" ); 473 _printer.printText( state.rawName ); 474 _printer.printText( '>' ); 475 } 476 } 477 state = leaveElementState(); 480 if ( htmlName == null || ( ! htmlName.equalsIgnoreCase( "A" ) && 482 ! htmlName.equalsIgnoreCase( "TD" ) ) ) 483 484 state.afterElement = true; 485 state.empty = false; 486 if ( isDocumentState() ) 487 _printer.flush(); 488 } 489 490 491 495 496 public void characters( char[] chars, int start, int length ) 497 throws SAXException 498 { 499 ElementState state; 500 501 try { 502 state = content(); 504 state.doCData = false; 505 super.characters( chars, start, length ); 506 } catch ( IOException except ) { 507 throw new SAXException ( except ); 508 } 509 } 510 511 512 public void startElement( String tagName, AttributeList attrs ) 513 throws SAXException 514 { 515 int i; 516 boolean preserveSpace; 517 ElementState state; 518 String name; 519 String value; 520 521 try { 522 if ( _printer == null ) 523 throw new IllegalStateException ( 524 DOMMessageFormatter.formatMessage( 525 DOMMessageFormatter.SERIALIZER_DOMAIN, 526 "NoWriterSupplied", null)); 527 528 529 state = getElementState(); 530 if ( isDocumentState() ) { 531 if ( ! _started ) 536 startDocument( tagName ); 537 } else { 538 if ( state.empty ) 542 _printer.printText( '>' ); 543 if ( _indenting && ! state.preserveSpace && 547 ( state.empty || state.afterElement ) ) 548 _printer.breakLine(); 549 } 550 preserveSpace = state.preserveSpace; 551 552 555 _printer.printText( '<' ); 557 if ( _xhtml ) 558 _printer.printText( tagName.toLowerCase(Locale.ENGLISH) ); 559 else 560 _printer.printText( tagName ); 561 _printer.indent(); 562 563 if ( attrs != null ) { 567 for ( i = 0 ; i < attrs.getLength() ; ++i ) { 568 _printer.printSpace(); 569 name = attrs.getName( i ).toLowerCase(Locale.ENGLISH); 570 value = attrs.getValue( i ); 571 if ( _xhtml ) { 572 if ( value == null ) { 574 _printer.printText( name ); 575 _printer.printText( "=\"\"" ); 576 } else { 577 _printer.printText( name ); 578 _printer.printText( "=\"" ); 579 printEscaped( value ); 580 _printer.printText( '"' ); 581 } 582 } else { 583 if ( value == null ) { 586 value = ""; 587 } 588 if ( !_format.getPreserveEmptyAttributes() && value.length() == 0 ) 589 _printer.printText( name ); 590 else if ( HTMLdtd.isURI( tagName, name ) ) { 591 _printer.printText( name ); 592 _printer.printText( "=\"" ); 593 _printer.printText( escapeURI( value ) ); 594 _printer.printText( '"' ); 595 } else if ( HTMLdtd.isBoolean( tagName, name ) ) 596 _printer.printText( name ); 597 else { 598 _printer.printText( name ); 599 _printer.printText( "=\"" ); 600 printEscaped( value ); 601 _printer.printText( '"' ); 602 } 603 } 604 } 605 } 606 if ( HTMLdtd.isPreserveSpace( tagName ) ) 607 preserveSpace = true; 608 609 state = enterElementState( null, null, tagName, preserveSpace ); 613 614 if ( tagName.equalsIgnoreCase( "A" ) || tagName.equalsIgnoreCase( "TD" ) ) { 616 state.empty = false; 617 _printer.printText( '>' ); 618 } 619 620 if ( tagName.equalsIgnoreCase( "SCRIPT" ) || 624 tagName.equalsIgnoreCase( "STYLE" ) ) { 625 if ( _xhtml ) { 626 state.doCData = true; 628 } else { 629 state.unescaped = true; 631 } 632 } 633 } catch ( IOException except ) { 634 throw new SAXException ( except ); 635 } 636 } 637 638 639 public void endElement( String tagName ) 640 throws SAXException 641 { 642 endElement( null, null, tagName ); 643 } 644 645 646 650 651 663 protected void startDocument( String rootTagName ) 664 throws IOException 665 { 666 StringBuffer buffer; 667 668 _printer.leaveDTD(); 671 if ( ! _started ) { 672 if ( _docTypePublicId == null && _docTypeSystemId == null ) { 676 if ( _xhtml ) { 677 _docTypePublicId = HTMLdtd.XHTMLPublicId; 678 _docTypeSystemId = HTMLdtd.XHTMLSystemId; 679 } else { 680 _docTypePublicId = HTMLdtd.HTMLPublicId; 681 _docTypeSystemId = HTMLdtd.HTMLSystemId; 682 } 683 } 684 685 if ( ! _format.getOmitDocumentType() ) { 686 if ( _docTypePublicId != null && ( ! _xhtml || _docTypeSystemId != null ) ) { 693 if (_xhtml) { 694 _printer.printText( "<!DOCTYPE html PUBLIC " ); 695 } 696 else { 697 _printer.printText( "<!DOCTYPE HTML PUBLIC " ); 698 } 699 printDoctypeURL( _docTypePublicId ); 700 if ( _docTypeSystemId != null ) { 701 if ( _indenting ) { 702 _printer.breakLine(); 703 _printer.printText( " " ); 704 } else 705 _printer.printText( ' ' ); 706 printDoctypeURL( _docTypeSystemId ); 707 } 708 _printer.printText( '>' ); 709 _printer.breakLine(); 710 } else if ( _docTypeSystemId != null ) { 711 if (_xhtml) { 712 _printer.printText( "<!DOCTYPE html SYSTEM " ); 713 } 714 else { 715 _printer.printText( "<!DOCTYPE HTML SYSTEM " ); 716 } 717 printDoctypeURL( _docTypeSystemId ); 718 _printer.printText( '>' ); 719 _printer.breakLine(); 720 } 721 } 722 } 723 724 _started = true; 725 serializePreRoot(); 727 } 728 729 730 735 protected void serializeElement( Element elem ) 736 throws IOException 737 { 738 Attr attr; 739 NamedNodeMap attrMap; 740 int i; 741 Node child; 742 ElementState state; 743 boolean preserveSpace; 744 String name; 745 String value; 746 String tagName; 747 748 tagName = elem.getTagName(); 749 state = getElementState(); 750 if ( isDocumentState() ) { 751 if ( ! _started ) 756 startDocument( tagName ); 757 } else { 758 if ( state.empty ) 762 _printer.printText( '>' ); 763 if ( _indenting && ! state.preserveSpace && 767 ( state.empty || state.afterElement ) ) 768 _printer.breakLine(); 769 } 770 preserveSpace = state.preserveSpace; 771 772 775 _printer.printText( '<' ); 777 if ( _xhtml ) 778 _printer.printText( tagName.toLowerCase(Locale.ENGLISH) ); 779 else 780 _printer.printText( tagName ); 781 _printer.indent(); 782 783 attrMap = elem.getAttributes(); 789 if ( attrMap != null ) { 790 for ( i = 0 ; i < attrMap.getLength() ; ++i ) { 791 attr = (Attr ) attrMap.item( i ); 792 name = attr.getName().toLowerCase(Locale.ENGLISH); 793 value = attr.getValue(); 794 if ( attr.getSpecified() ) { 795 _printer.printSpace(); 796 if ( _xhtml ) { 797 if ( value == null ) { 799 _printer.printText( name ); 800 _printer.printText( "=\"\"" ); 801 } else { 802 _printer.printText( name ); 803 _printer.printText( "=\"" ); 804 printEscaped( value ); 805 _printer.printText( '"' ); 806 } 807 } else { 808 if ( value == null ) { 811 value = ""; 812 } 813 if ( !_format.getPreserveEmptyAttributes() && value.length() == 0 ) 814 _printer.printText( name ); 815 else if ( HTMLdtd.isURI( tagName, name ) ) { 816 _printer.printText( name ); 817 _printer.printText( "=\"" ); 818 _printer.printText( escapeURI( value ) ); 819 _printer.printText( '"' ); 820 } else if ( HTMLdtd.isBoolean( tagName, name ) ) 821 _printer.printText( name ); 822 else { 823 _printer.printText( name ); 824 _printer.printText( "=\"" ); 825 printEscaped( value ); 826 _printer.printText( '"' ); 827 } 828 } 829 } 830 } 831 } 832 if ( HTMLdtd.isPreserveSpace( tagName ) ) 833 preserveSpace = true; 834 835 if ( elem.hasChildNodes() || ! HTMLdtd.isEmptyTag( tagName ) ) { 838 state = enterElementState( null, null, tagName, preserveSpace ); 841 842 if ( tagName.equalsIgnoreCase( "A" ) || tagName.equalsIgnoreCase( "TD" ) ) { 844 state.empty = false; 845 _printer.printText( '>' ); 846 } 847 848 if ( tagName.equalsIgnoreCase( "SCRIPT" ) || 852 tagName.equalsIgnoreCase( "STYLE" ) ) { 853 if ( _xhtml ) { 854 state.doCData = true; 856 } else { 857 state.unescaped = true; 859 } 860 } 861 child = elem.getFirstChild(); 862 while ( child != null ) { 863 serializeNode( child ); 864 child = child.getNextSibling(); 865 } 866 endElementIO( null, null, tagName ); 867 } else { 868 _printer.unindent(); 869 if ( _xhtml ) 872 _printer.printText( " />" ); 873 else 874 _printer.printText( '>' ); 875 state.afterElement = true; 877 state.empty = false; 878 if ( isDocumentState() ) 879 _printer.flush(); 880 } 881 } 882 883 884 885 protected void characters( String text ) 886 throws IOException 887 { 888 ElementState state; 889 890 state = content(); 892 super.characters( text ); 893 } 894 895 896 protected String getEntityRef( int ch ) 897 { 898 return HTMLdtd.fromChar( ch ); 899 } 900 901 902 protected String escapeURI( String uri ) 903 { 904 int index; 905 906 index = uri.indexOf( "\"" ); 909 if ( index >= 0 ) 910 return uri.substring( 0, index ); 911 else 912 return uri; 913 } 914 915 916 } 917 918 919 920 921 | Popular Tags |