1 19 package org.netbeans.tax.io; 20 21 import java.lang.reflect.*; 22 23 import java.io.Writer ; 24 import java.io.StringWriter ; 25 import java.io.OutputStream ; 26 import java.io.OutputStreamWriter ; 27 import java.io.IOException ; 28 import java.io.UnsupportedEncodingException ; 29 import java.io.PipedWriter ; 30 31 import java.util.Iterator ; 32 import java.util.List ; 33 import java.util.StringTokenizer ; 34 35 import java.text.MessageFormat ; 36 37 import org.netbeans.tax.TreeException; 38 import org.netbeans.tax.TreeDocumentRoot; 39 import org.netbeans.tax.TreeNode; 40 import org.netbeans.tax.TreeChild; 41 import org.netbeans.tax.TreeObjectList; 42 import org.netbeans.tax.TreeParentNode; 43 44 import org.netbeans.tax.TreeAttlistDecl; 45 import org.netbeans.tax.TreeAttlistDeclAttributeDef; 46 import org.netbeans.tax.TreeAttribute; 47 import org.netbeans.tax.TreeCDATASection; 48 import org.netbeans.tax.TreeCharacterReference; 49 import org.netbeans.tax.TreeCharacterData; 50 import org.netbeans.tax.TreeComment; 51 import org.netbeans.tax.TreeConditionalSection; 52 import org.netbeans.tax.TreeDocumentFragment; 53 import org.netbeans.tax.TreeDocument; 54 import org.netbeans.tax.TreeDocumentType; 55 import org.netbeans.tax.TreeDTD; 56 import org.netbeans.tax.TreeElementDecl; 57 import org.netbeans.tax.TreeElement; 58 import org.netbeans.tax.TreeEntityDecl; 59 import org.netbeans.tax.TreeGeneralEntityReference; 60 import org.netbeans.tax.TreeNotationDecl; 61 import org.netbeans.tax.TreeParameterEntityReference; 62 import org.netbeans.tax.TreeProcessingInstruction; 63 import org.netbeans.tax.TreeText; 64 import org.netbeans.tax.TreeUtilities; 65 66 import org.netbeans.tax.spec.AttlistDecl; 67 import org.netbeans.tax.spec.Attribute; 68 import org.netbeans.tax.spec.CDATASection; 69 import org.netbeans.tax.spec.CharacterReference; 70 import org.netbeans.tax.spec.Comment; 71 import org.netbeans.tax.spec.ConditionalSection; 72 import org.netbeans.tax.spec.DocumentFragment; 73 import org.netbeans.tax.spec.Document; 74 import org.netbeans.tax.spec.DocumentType; 75 import org.netbeans.tax.spec.DTD; 76 import org.netbeans.tax.spec.ElementDecl; 77 import org.netbeans.tax.spec.Element; 78 import org.netbeans.tax.spec.EntityDecl; 79 import org.netbeans.tax.spec.GeneralEntityReference; 80 import org.netbeans.tax.spec.NotationDecl; 81 import org.netbeans.tax.spec.ParameterEntityReference; 82 import org.netbeans.tax.spec.ProcessingInstruction; 83 import org.netbeans.tax.spec.Text; 84 85 95 public class TreeStreamResult implements TreeOutputResult { 96 97 98 private TreeStreamWriter writer; 99 100 101 105 106 public TreeStreamResult (OutputStream outputStream) { 107 this.writer = new TreeStreamWriter (outputStream); 108 } 109 110 111 public TreeStreamResult (StringWriter writer) { 112 this.writer = new TreeStreamWriter (writer); 113 } 114 115 public TreeStreamResult (PipedWriter writer) { 116 this.writer = new TreeStreamWriter (writer); 117 } 118 119 123 125 public final TreeWriter getWriter (TreeDocumentRoot document) { 126 writer.setDocument (document); 127 return writer; 128 } 129 130 131 135 138 public final static class TreeStreamWriter 139 implements TreeWriter, 140 AttlistDecl.Writer, 141 Attribute.Writer, 142 CDATASection.Writer, 143 CharacterReference.Writer, 144 Comment.Writer, 145 ConditionalSection.Writer, 146 DocumentFragment.Writer, 147 Document.Writer, 148 DocumentType.Writer, 149 DTD.Writer, 150 ElementDecl.Writer, 151 Element.Writer, 152 EntityDecl.Writer, 153 GeneralEntityReference.Writer, 154 NotationDecl.Writer, 155 ParameterEntityReference.Writer, 156 ProcessingInstruction.Writer, 157 Text.Writer { 158 159 private static final char LESS_THAN = '<'; 160 private static final char GREAT_THAN = '>'; 161 private static final char AMPERSAND = '&'; 162 private static final char SEMICOLON = ';'; 163 private static final char APOSTROPHE = '\''; 164 private static final char QUOTE = '"'; 165 private static final char PER_CENT = '%'; 166 private static final char ASSIGN = '='; 167 private static final char BRACKET_LEFT = '['; 168 private static final char SPACE = ' '; 169 170 private static final String PI_START = "<?"; private static final String PI_END = "?>"; private static final String COMMENT_START = "<!--"; private static final String COMMENT_END = "-->"; private static final String ELEMENT_EMPTY_END = " />"; private static final String ELEMENT_END_START = "</"; private static final String CDATA_START = "<![CDATA["; private static final String CDATA_END = "]]>"; private static final String DOCTYPE_START = "<!DOCTYPE "; private static final String DOCTYPE_INTERN_END = "]]>"; private static final String CHAR_REF_START = "&#"; private static final String CHAR_REF_HEX_START = "&#x"; 183 private static final String ELEMENT_DECL_START = "<!ELEMENT "; private static final String ATTLIST_DECL_START = "<!ATTLIST "; private static final String ENTITY_DECL_START = "<!ENTITY "; private static final String NOTATION_DECL_START = "<!NOTATION "; 188 private static final String XML_HEADER = "<?xml "; private static final String XML_VERSION = "version"; private static final String XML_ENCODING = "encoding"; private static final String XML_STANDALONE = "standalone"; 193 private static final String PUBLIC = "PUBLIC "; private static final String SYSTEM = "SYSTEM "; 196 197 198 private OutputStream outputStream; 199 200 201 private Writer writer; 202 203 204 private TreeDocumentRoot document; 205 206 207 private int indent = 0; 208 209 private int indent_step = 4; 210 211 212 216 217 public TreeStreamWriter (OutputStream outputStream) { 218 this.outputStream = outputStream; 219 } 220 221 222 public TreeStreamWriter (StringWriter writer) { 223 this.writer = writer; 224 } 225 226 229 public TreeStreamWriter (PipedWriter writer) { 230 this.writer = writer; 231 } 232 233 237 239 public OutputStream getOutputStream () { 240 return outputStream; 241 } 242 243 245 public Writer getWriter () { 246 return writer; 247 } 248 249 251 public void setDocument (TreeDocumentRoot document) { 252 this.document = document; 253 } 254 255 257 public void writeDocument () throws TreeException { 258 String encoding = document.getEncoding (); 259 if ( outputStream != null ) { 260 try { 261 262 if (encoding != null) { 263 encoding = TreeUtilities.iana2java (encoding); 264 } 265 266 writer = (encoding == null ? new OutputStreamWriter (outputStream): new OutputStreamWriter (outputStream, encoding)); 267 } catch (UnsupportedEncodingException exc) { 268 throw new TreeException (exc); 269 } 270 } 271 writeNode ((TreeNode)document); 272 273 try { 274 writer.flush (); 275 } catch (IOException ex) { 276 throw new TreeException (ex); 277 } 278 } 279 280 282 public void writeNode (TreeNode node) throws TreeException { 283 if ( node instanceof TreeAttlistDecl ) { 285 writeAttlistDecl ((TreeAttlistDecl)node); 286 } else if ( node instanceof TreeAttribute ) { 287 writeAttribute ((TreeAttribute)node); 288 } else if ( node instanceof TreeCDATASection ) { 289 writeCDATASection ((TreeCDATASection)node); 290 } else if ( node instanceof TreeCharacterReference ) { 291 writeCharacterReference ((TreeCharacterReference)node); 292 } else if ( node instanceof TreeComment ) { 293 writeComment ((TreeComment)node); 294 } else if ( node instanceof TreeConditionalSection ) { 295 writeConditionalSection ((TreeConditionalSection)node); 296 } else if ( node instanceof TreeDocumentFragment ) { 297 writeDocumentFragment ((TreeDocumentFragment)node); 298 } else if ( node instanceof TreeDocument ) { 299 writeDocument ((TreeDocument)node); 300 } else if ( node instanceof TreeDocumentType ) { 301 writeDocumentType ((TreeDocumentType)node); 302 } else if ( node instanceof TreeDTD ) { 303 writeDTD ((TreeDTD)node); 304 } else if ( node instanceof TreeElementDecl ) { 305 writeElementDecl ((TreeElementDecl)node); 306 } else if ( node instanceof TreeElement ) { 307 writeElement ((TreeElement)node); 308 } else if ( node instanceof TreeEntityDecl ) { 309 writeEntityDecl ((TreeEntityDecl)node); 310 } else if ( node instanceof TreeGeneralEntityReference ) { 311 writeGeneralEntityReference ((TreeGeneralEntityReference)node); 312 } else if ( node instanceof TreeNotationDecl ) { 313 writeNotationDecl ((TreeNotationDecl)node); 314 } else if ( node instanceof TreeParameterEntityReference ) { 315 writeParameterEntityReference ((TreeParameterEntityReference)node); 316 } else if ( node instanceof TreeProcessingInstruction ) { 317 writeProcessingInstruction ((TreeProcessingInstruction)node); 318 } else if ( node instanceof TreeText ) { 319 writeText ((TreeText)node); 320 } 321 } 322 323 324 328 330 public void writeAttlistDecl (TreeAttlistDecl attlistDecl) throws TreeException { 331 StringBuffer sb = new StringBuffer (); 332 sb.append (ATTLIST_DECL_START).append (attlistDecl.getElementName ()); 333 334 List attrdefs = attlistDecl.getAttributeDefs (); 335 Iterator it = attrdefs.iterator (); 336 while (it.hasNext ()) { 337 TreeAttlistDeclAttributeDef attrDef = (TreeAttlistDeclAttributeDef)it.next (); 338 339 sb.append ("\n\t").append (attrDef.getName ()).append (SPACE); if (attrDef.getType () != attrDef.TYPE_ENUMERATED) { 341 sb.append (attrDef.getTypeName ()).append (SPACE); 342 } 343 if ((attrDef.getType () == TreeAttlistDeclAttributeDef.TYPE_ENUMERATED) || 344 (attrDef.getType () == TreeAttlistDeclAttributeDef.TYPE_NOTATION)) { 345 sb.append (attrDef.getEnumeratedTypeString ()).append (SPACE); 346 } 347 if (attrDef.getDefaultType () != TreeAttlistDeclAttributeDef.DEFAULT_TYPE_NULL) { 348 sb.append (attrDef.getDefaultTypeName ()).append (SPACE); 349 } 350 if ((attrDef.getDefaultType () == TreeAttlistDeclAttributeDef.DEFAULT_TYPE_FIXED) || 351 (attrDef.getDefaultType () == TreeAttlistDeclAttributeDef.DEFAULT_TYPE_NULL)) { 352 sb.append ("\"").append (attrDef.getDefaultValue ()).append ("\""); } 354 } 355 356 sb.append (GREAT_THAN); 357 write (sb.toString ()); 358 } 359 360 363 public void writeAttribute (TreeAttribute attribute) throws TreeException { 364 if (attribute.isSpecified () == false) 365 return; 366 write (createValueString (attribute.getQName (), attribute.getNonNormalizedValue ())); 367 368 } 369 370 372 public void writeCDATASection (TreeCDATASection cdataSection) throws TreeException { 373 String cdataData = cdataSection.getData (); 374 String cdataString = MessageFormat.format ("<![CDATA[{0}]]>", new Object [] { cdataData }); write (cdataString); 376 } 377 378 380 public void writeCharacterReference (TreeCharacterReference characterReference) throws TreeException { 381 String refName = characterReference.getName (); 382 String refString = MessageFormat.format ("&{0};", new Object [] { refName }); write (refString); 384 } 385 386 388 public void writeComment (TreeComment comment) throws TreeException { 389 String comName = comment.getData (); 390 String comString = MessageFormat.format ("<!--{0}-->", new Object [] { comName }); write (comString); 392 } 393 394 396 public void writeConditionalSection (TreeConditionalSection conditionalSection) throws TreeException { 397 if ( conditionalSection.isInclude () ) { 398 write ("<![ INCLUDE [\n"); writeObjectList (conditionalSection); 400 } else { 401 write ("<![ IGNORE ["); write (conditionalSection.getIgnoredContent ()); 403 } 404 write ("]]>"); } 406 407 409 public void writeDocumentFragment (TreeDocumentFragment documentFragment) throws TreeException { 410 StringBuffer sb = new StringBuffer (); 411 412 StringBuffer header = null; 413 if (documentFragment.getVersion () != null) { 414 if (header == null) 415 header = new StringBuffer (); 416 header.append (createValueString (XML_VERSION, documentFragment.getVersion ())).append (SPACE); 417 } 418 if (documentFragment.getEncoding () != null) { 419 if (header == null) 420 header = new StringBuffer (); 421 header.append (createValueString (XML_ENCODING, documentFragment.getEncoding ())); 422 } 423 if (header != null) { 424 sb.append (XML_HEADER).append (header).append (PI_END); 425 } 426 write (sb.toString () + "\n\n"); 428 indent -= indent_step; 429 writeObjectList (documentFragment); 430 } 431 432 434 public void writeDocument (TreeDocument document) throws TreeException { 435 StringBuffer sb = new StringBuffer (); 436 437 StringBuffer header = null; 438 if (document.getVersion () != null) { 439 if (header == null) 440 header = new StringBuffer (); 441 header.append (createValueString (XML_VERSION, document.getVersion ())); 442 } 443 if (document.getEncoding () != null) { 444 if (header == null) 445 header = new StringBuffer (); 446 header.append (SPACE).append (createValueString (XML_ENCODING, document.getEncoding ())); 447 } 448 if (document.getStandalone () != null) { 449 if (header == null) 450 header = new StringBuffer (); 451 header.append (SPACE).append (createValueString (XML_STANDALONE, document.getStandalone ())); 452 } 453 if (header != null) { 454 sb.append (XML_HEADER).append (header).append (PI_END); 455 } 456 write(sb.toString() + "\n"); 458 indent -= indent_step; 459 writeObjectList (document); 460 } 461 462 464 public void writeDocumentType (TreeDocumentType documentType) throws TreeException { 465 StringBuffer sb = new StringBuffer (); 466 467 sb.append (DOCTYPE_START).append (documentType.getElementName ()); 468 if (documentType.getPublicId () != null) { 469 sb.append (SPACE).append (PUBLIC); 470 sb.append (createQuoteString (documentType.getPublicId ())).append (SPACE); 471 String systemId = documentType.getSystemId (); 472 sb.append (createQuoteString (systemId == null ? "" : systemId)); } else if (documentType.getSystemId () != null) { 474 sb.append (SPACE).append (SYSTEM); 475 sb.append (createQuoteString (documentType.getSystemId ())); 476 } 477 write (sb.toString ()); 478 479 if ( documentType.hasChildNodes () ) { 480 write (" ["); 482 484 try { 485 if (documentType == null) return; 486 Class klass = documentType.getClass (); 487 Field field = klass.getDeclaredField ("internalDTDText"); field.setAccessible (true); 489 490 String internalDTDText = (String )field.get (documentType); 491 492 if ( internalDTDText != null ) { 493 write (internalDTDText); 494 } else { 495 write ("\n"); writeObjectList (documentType); 498 } 499 } catch (RuntimeException ex) { 500 throw ex; 501 } catch (Exception ex) { 502 write ("\n"); writeObjectList (documentType); 505 } 506 507 write ("]"); } 509 510 write (GREAT_THAN); } 512 513 515 public void writeDTD (TreeDTD dtd) throws TreeException { 516 StringBuffer sb = new StringBuffer (); 517 518 StringBuffer header = null; 519 if (dtd.getVersion () != null) { 520 if (header == null) 521 header = new StringBuffer (); 522 header.append (createValueString (XML_VERSION, dtd.getVersion ())).append (SPACE); 523 } 524 if (dtd.getEncoding () != null) { 525 if (header == null) 526 header = new StringBuffer (); 527 header.append (createValueString (XML_ENCODING, dtd.getEncoding ())); 528 } 529 if (header != null) { 530 sb.append (XML_HEADER).append (header).append (PI_END); 531 } 532 write (sb.toString () + "\n\n"); 534 indent -= indent_step; 535 writeObjectList (dtd); 536 } 537 538 540 public void writeElementDecl (TreeElementDecl elementDecl) throws TreeException { 541 StringBuffer sb = new StringBuffer (); 542 sb.append (ELEMENT_DECL_START).append (elementDecl.getName ()).append (SPACE); 543 sb.append (elementDecl.getContentType ().toString ()); 544 sb.append (GREAT_THAN); 545 write (sb.toString ()); 546 } 547 548 550 public void writeElement (TreeElement element) throws TreeException { 551 String elemName = element.getQName (); 552 write ("<" + elemName); 554 Iterator it = element.getAttributes ().iterator (); 555 while ( it.hasNext () ) { 556 TreeAttribute attr = (TreeAttribute)it.next (); 557 if (attr.isSpecified ()) { 558 write (SPACE); 559 writeAttribute (attr); 560 } 561 } 562 563 if (element.isEmpty ()) { 564 565 write ("/>"); 567 } else { 568 write (">"); 570 writeObjectList (element); 572 573 String endElemString = MessageFormat.format ("</{0}>", new Object [] { elemName }); write (endElemString); 576 } 577 } 578 579 581 public void writeEntityDecl (TreeEntityDecl entityDecl) throws TreeException { 582 String entParam = entityDecl.isParameter () ? "% " : ""; String entName = entityDecl.getName (); 584 String entType = ""; switch (entityDecl.getType ()) { 586 case TreeEntityDecl.TYPE_INTERNAL: 587 entType = "\"" + entityDecl.getInternalText () + "\""; break; 589 case TreeEntityDecl.TYPE_EXTERNAL: 590 entType = createExternalIdString (entityDecl.getPublicId (), entityDecl.getSystemId ()); 591 break; 592 case TreeEntityDecl.TYPE_UNPARSED: 593 entType = createExternalIdString (entityDecl.getPublicId (), entityDecl.getSystemId ()) + 594 " NDATA " + entityDecl.getNotationName (); break; 596 } 597 String entString = MessageFormat.format ("<!ENTITY {0}{1} {2}>", new Object [] { entParam, entName, entType }); write (entString); 599 } 600 601 603 public void writeGeneralEntityReference (TreeGeneralEntityReference generalEntityReference) throws TreeException { 604 String refName = generalEntityReference.getName (); 605 String refString = MessageFormat.format 606 ("&{0};", new Object [] { refName }); write (refString); 608 } 609 610 612 public void writeNotationDecl (TreeNotationDecl notationDecl) throws TreeException { 613 String notName = notationDecl.getName (); 614 String notSysId = notationDecl.getSystemId (); 615 String notPubId = notationDecl.getPublicId (); 616 String notExtId = createExternalIdString (notPubId, notSysId); 617 String notString = MessageFormat.format 618 ("<!NOTATION {0} {1}>", new Object [] { notName, notExtId }); write (notString); 620 } 621 622 624 public void writeParameterEntityReference (TreeParameterEntityReference parameterEntityReference) throws TreeException { 625 String refName = parameterEntityReference.getName (); 626 String refString = MessageFormat.format 627 ("%{0};", new Object [] { refName }); write (refString); 629 } 630 631 633 public void writeProcessingInstruction (TreeProcessingInstruction processingInstruction) throws TreeException { 634 String piTarget = processingInstruction.getTarget (); 635 String piData = processingInstruction.getData (); 636 String piString = MessageFormat.format 637 ("<?{0} {1}?>", new Object [] { piTarget, piData }); write (piString); 639 } 640 641 643 public void writeText (TreeText text) throws TreeException { 644 String textString = text.getData (); 645 write (textString); 646 } 647 648 649 653 private void write (String string) throws TreeException { 654 try { 655 writer.write (string); 656 } catch (IOException exc) { 657 throw new TreeException (exc); 658 } 659 } 660 661 private void write (char ch) throws TreeException { 662 try { 663 writer.write (ch); 664 } catch (IOException exc) { 665 throw new TreeException (exc); 666 } 667 } 668 669 private void startIndent () throws TreeException { 670 StringBuffer sb = new StringBuffer (); 671 for (int i = 0; i < indent; i++) { 672 sb.append (' '); 673 } 674 try { 675 writer.write (sb.toString ()); 676 } catch (IOException exc) { 677 throw new TreeException (exc); 678 } 679 } 680 681 private void endIndent () throws TreeException { 682 write ("\n"); } 684 685 private void writeObjectList (TreeParentNode parentNode) throws TreeException { 686 indent += indent_step; 687 688 boolean notElementChild = ( parentNode instanceof TreeElement ) == false; 689 boolean documentChild = ( parentNode instanceof TreeDocument ) == true; 690 691 Iterator it = parentNode.getChildNodes ().iterator (); 692 while ( it.hasNext () ) { 693 TreeNode node = (TreeNode)it.next (); 694 696 if ( notElementChild ) { 697 startIndent (); 699 } 700 701 writeNode (node); 702 703 if ( notElementChild ) { 704 endIndent (); 706 } 707 } 708 indent -= indent_step; 709 } 710 711 712 715 private String createValueString (String name, String value) { 716 String valueString = MessageFormat.format 717 ("{0}={1}", new Object [] { name, createQuoteString (value) }); return valueString; 719 } 720 721 724 private String createQuoteString (String value) { 725 Character quote = new Character (QUOTE); 726 if ( value.indexOf (QUOTE) != -1 ) { 727 quote = new Character (APOSTROPHE); 728 } 729 return createQuoteString (value, quote); 730 } 731 732 734 private String createQuoteString (String value, Character quote) { 735 String valueString = MessageFormat.format 736 ("{1}{0}{1}", new Object [] { value, quote }); return valueString; 738 } 739 740 742 private String createExternalIdString (String publicId, String systemId) { 743 String externId; 744 if (publicId == null) { 745 externId = MessageFormat.format 746 ("SYSTEM {0}", new Object [] { createQuoteString (systemId) }); } else if (systemId == null) { 748 externId = MessageFormat.format 749 ("PUBLIC {0}", new Object [] { createQuoteString (publicId) }); } else { 751 externId = MessageFormat.format 752 ("PUBLIC {0} {1}", new Object [] { createQuoteString (publicId), createQuoteString (systemId) }); } 754 return externId; 755 } 756 757 } 759 } 760 | Popular Tags |