001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.tax.io;
042:
043: import java.lang.reflect.*;
044:
045: import java.io.Writer;
046: import java.io.StringWriter;
047: import java.io.OutputStream;
048: import java.io.OutputStreamWriter;
049: import java.io.IOException;
050: import java.io.UnsupportedEncodingException;
051: import java.io.PipedWriter;
052:
053: import java.util.Iterator;
054: import java.util.List;
055: import java.util.StringTokenizer;
056:
057: import java.text.MessageFormat;
058:
059: import org.netbeans.tax.TreeException;
060: import org.netbeans.tax.TreeDocumentRoot;
061: import org.netbeans.tax.TreeNode;
062: import org.netbeans.tax.TreeChild;
063: import org.netbeans.tax.TreeObjectList;
064: import org.netbeans.tax.TreeParentNode;
065:
066: import org.netbeans.tax.TreeAttlistDecl;
067: import org.netbeans.tax.TreeAttlistDeclAttributeDef;
068: import org.netbeans.tax.TreeAttribute;
069: import org.netbeans.tax.TreeCDATASection;
070: import org.netbeans.tax.TreeCharacterReference;
071: import org.netbeans.tax.TreeCharacterData;
072: import org.netbeans.tax.TreeComment;
073: import org.netbeans.tax.TreeConditionalSection;
074: import org.netbeans.tax.TreeDocumentFragment;
075: import org.netbeans.tax.TreeDocument;
076: import org.netbeans.tax.TreeDocumentType;
077: import org.netbeans.tax.TreeDTD;
078: import org.netbeans.tax.TreeElementDecl;
079: import org.netbeans.tax.TreeElement;
080: import org.netbeans.tax.TreeEntityDecl;
081: import org.netbeans.tax.TreeGeneralEntityReference;
082: import org.netbeans.tax.TreeNotationDecl;
083: import org.netbeans.tax.TreeParameterEntityReference;
084: import org.netbeans.tax.TreeProcessingInstruction;
085: import org.netbeans.tax.TreeText;
086: import org.netbeans.tax.TreeUtilities;
087:
088: import org.netbeans.tax.spec.AttlistDecl;
089: import org.netbeans.tax.spec.Attribute;
090: import org.netbeans.tax.spec.CDATASection;
091: import org.netbeans.tax.spec.CharacterReference;
092: import org.netbeans.tax.spec.Comment;
093: import org.netbeans.tax.spec.ConditionalSection;
094: import org.netbeans.tax.spec.DocumentFragment;
095: import org.netbeans.tax.spec.Document;
096: import org.netbeans.tax.spec.DocumentType;
097: import org.netbeans.tax.spec.DTD;
098: import org.netbeans.tax.spec.ElementDecl;
099: import org.netbeans.tax.spec.Element;
100: import org.netbeans.tax.spec.EntityDecl;
101: import org.netbeans.tax.spec.GeneralEntityReference;
102: import org.netbeans.tax.spec.NotationDecl;
103: import org.netbeans.tax.spec.ParameterEntityReference;
104: import org.netbeans.tax.spec.ProcessingInstruction;
105: import org.netbeans.tax.spec.Text;
106:
107: /**
108: * We should avoid MessageFormat usage, it is probably the slowest method
109: * for constructing output.
110: * <p>
111: * Fast implementation would write directly to steam/StringBuffer without
112: * construction so many auxiliary Strings.
113: *
114: * @author Libor Kramolis
115: * @version 0.1
116: */
117: public class TreeStreamResult implements TreeOutputResult {
118:
119: /** */
120: private TreeStreamWriter writer;
121:
122: //
123: // init
124: //
125:
126: /** Creates new TreeStreamResult. */
127: public TreeStreamResult(OutputStream outputStream) {
128: this .writer = new TreeStreamWriter(outputStream);
129: }
130:
131: /** Creates new TreeStreamResult. */
132: public TreeStreamResult(StringWriter writer) {
133: this .writer = new TreeStreamWriter(writer);
134: }
135:
136: public TreeStreamResult(PipedWriter writer) {
137: this .writer = new TreeStreamWriter(writer);
138: }
139:
140: //
141: // itself
142: //
143:
144: /**
145: */
146: public final TreeWriter getWriter(TreeDocumentRoot document) {
147: writer.setDocument(document);
148: return writer;
149: }
150:
151: //
152: // Writer
153: //
154:
155: /**
156: *
157: */
158: public final static class TreeStreamWriter implements TreeWriter,
159: AttlistDecl.Writer, Attribute.Writer, CDATASection.Writer,
160: CharacterReference.Writer, Comment.Writer,
161: ConditionalSection.Writer, DocumentFragment.Writer,
162: Document.Writer, DocumentType.Writer, DTD.Writer,
163: ElementDecl.Writer, Element.Writer, EntityDecl.Writer,
164: GeneralEntityReference.Writer, NotationDecl.Writer,
165: ParameterEntityReference.Writer,
166: ProcessingInstruction.Writer, Text.Writer {
167:
168: private static final char LESS_THAN = '<';
169: private static final char GREAT_THAN = '>';
170: private static final char AMPERSAND = '&';
171: private static final char SEMICOLON = ';';
172: private static final char APOSTROPHE = '\'';
173: private static final char QUOTE = '"';
174: private static final char PER_CENT = '%';
175: private static final char ASSIGN = '=';
176: private static final char BRACKET_LEFT = '[';
177: private static final char SPACE = ' ';
178:
179: private static final String PI_START = "<?"; // NOI18N
180: private static final String PI_END = "?>"; // NOI18N
181: private static final String COMMENT_START = "<!--"; // NOI18N
182: private static final String COMMENT_END = "-->"; // NOI18N
183: private static final String ELEMENT_EMPTY_END = " />"; // NOI18N
184: private static final String ELEMENT_END_START = "</"; // NOI18N
185: private static final String CDATA_START = "<![CDATA["; // NOI18N
186: private static final String CDATA_END = "]]>"; // NOI18N
187: private static final String DOCTYPE_START = "<!DOCTYPE "; // NOI18N
188: private static final String DOCTYPE_INTERN_END = "]]>"; // NOI18N
189: private static final String CHAR_REF_START = "&#"; // NOI18N
190: private static final String CHAR_REF_HEX_START = "&#x"; // NOI18N
191:
192: private static final String ELEMENT_DECL_START = "<!ELEMENT "; // NOI18N
193: private static final String ATTLIST_DECL_START = "<!ATTLIST "; // NOI18N
194: private static final String ENTITY_DECL_START = "<!ENTITY "; // NOI18N
195: private static final String NOTATION_DECL_START = "<!NOTATION "; // NOI18N
196:
197: private static final String XML_HEADER = "<?xml "; // NOI18N
198: private static final String XML_VERSION = "version"; // NOI18N
199: private static final String XML_ENCODING = "encoding"; // NOI18N
200: private static final String XML_STANDALONE = "standalone"; // NOI18N
201:
202: private static final String PUBLIC = "PUBLIC "; // NOI18N
203: private static final String SYSTEM = "SYSTEM "; // NOI18N
204:
205: /** */
206: private OutputStream outputStream;
207:
208: /** */
209: private Writer writer;
210:
211: /** */
212: private TreeDocumentRoot document;
213:
214: /** */
215: private int indent = 0;
216: /** */
217: private int indent_step = 4;
218:
219: //
220: // init
221: //
222:
223: /** Creates new TreeStreamWriter. */
224: public TreeStreamWriter(OutputStream outputStream) {
225: this .outputStream = outputStream;
226: }
227:
228: /** Creates new TreeStreamWriter. */
229: public TreeStreamWriter(StringWriter writer) {
230: this .writer = writer;
231: }
232:
233: /**
234: * Create it writing result in pipe (convertable to Reader).
235: */
236: public TreeStreamWriter(PipedWriter writer) {
237: this .writer = writer;
238: }
239:
240: //
241: // itself
242: //
243:
244: /**
245: */
246: public OutputStream getOutputStream() {
247: return outputStream;
248: }
249:
250: /**
251: */
252: public Writer getWriter() {
253: return writer;
254: }
255:
256: /**
257: */
258: public void setDocument(TreeDocumentRoot document) {
259: this .document = document;
260: }
261:
262: /**
263: */
264: public void writeDocument() throws TreeException {
265: String encoding = document.getEncoding();
266: if (outputStream != null) {
267: try {
268:
269: if (encoding != null) {
270: encoding = TreeUtilities.iana2java(encoding);
271: }
272:
273: writer = (encoding == null ? new OutputStreamWriter(
274: outputStream)
275: : new OutputStreamWriter(outputStream,
276: encoding));
277: } catch (UnsupportedEncodingException exc) {
278: throw new TreeException(exc);
279: }
280: }
281: writeNode((TreeNode) document);
282:
283: try {
284: writer.flush();
285: } catch (IOException ex) {
286: throw new TreeException(ex);
287: }
288: }
289:
290: /**
291: */
292: public void writeNode(TreeNode node) throws TreeException {
293: //if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug("wriritng " + node); // NOI18N
294: if (node instanceof TreeAttlistDecl) {
295: writeAttlistDecl((TreeAttlistDecl) node);
296: } else if (node instanceof TreeAttribute) {
297: writeAttribute((TreeAttribute) node);
298: } else if (node instanceof TreeCDATASection) {
299: writeCDATASection((TreeCDATASection) node);
300: } else if (node instanceof TreeCharacterReference) {
301: writeCharacterReference((TreeCharacterReference) node);
302: } else if (node instanceof TreeComment) {
303: writeComment((TreeComment) node);
304: } else if (node instanceof TreeConditionalSection) {
305: writeConditionalSection((TreeConditionalSection) node);
306: } else if (node instanceof TreeDocumentFragment) {
307: writeDocumentFragment((TreeDocumentFragment) node);
308: } else if (node instanceof TreeDocument) {
309: writeDocument((TreeDocument) node);
310: } else if (node instanceof TreeDocumentType) {
311: writeDocumentType((TreeDocumentType) node);
312: } else if (node instanceof TreeDTD) {
313: writeDTD((TreeDTD) node);
314: } else if (node instanceof TreeElementDecl) {
315: writeElementDecl((TreeElementDecl) node);
316: } else if (node instanceof TreeElement) {
317: writeElement((TreeElement) node);
318: } else if (node instanceof TreeEntityDecl) {
319: writeEntityDecl((TreeEntityDecl) node);
320: } else if (node instanceof TreeGeneralEntityReference) {
321: writeGeneralEntityReference((TreeGeneralEntityReference) node);
322: } else if (node instanceof TreeNotationDecl) {
323: writeNotationDecl((TreeNotationDecl) node);
324: } else if (node instanceof TreeParameterEntityReference) {
325: writeParameterEntityReference((TreeParameterEntityReference) node);
326: } else if (node instanceof TreeProcessingInstruction) {
327: writeProcessingInstruction((TreeProcessingInstruction) node);
328: } else if (node instanceof TreeText) {
329: writeText((TreeText) node);
330: }
331: }
332:
333: //
334: // from <Node>.Writer
335: //
336:
337: /**
338: */
339: public void writeAttlistDecl(TreeAttlistDecl attlistDecl)
340: throws TreeException {
341: StringBuffer sb = new StringBuffer();
342: sb.append(ATTLIST_DECL_START).append(
343: attlistDecl.getElementName());
344:
345: List attrdefs = attlistDecl.getAttributeDefs();
346: Iterator it = attrdefs.iterator();
347: while (it.hasNext()) {
348: TreeAttlistDeclAttributeDef attrDef = (TreeAttlistDeclAttributeDef) it
349: .next();
350:
351: sb.append("\n\t").append(attrDef.getName()).append(
352: SPACE); // NOI18N
353: if (attrDef.getType() != attrDef.TYPE_ENUMERATED) {
354: sb.append(attrDef.getTypeName()).append(SPACE);
355: }
356: if ((attrDef.getType() == TreeAttlistDeclAttributeDef.TYPE_ENUMERATED)
357: || (attrDef.getType() == TreeAttlistDeclAttributeDef.TYPE_NOTATION)) {
358: sb.append(attrDef.getEnumeratedTypeString())
359: .append(SPACE);
360: }
361: if (attrDef.getDefaultType() != TreeAttlistDeclAttributeDef.DEFAULT_TYPE_NULL) {
362: sb.append(attrDef.getDefaultTypeName()).append(
363: SPACE);
364: }
365: if ((attrDef.getDefaultType() == TreeAttlistDeclAttributeDef.DEFAULT_TYPE_FIXED)
366: || (attrDef.getDefaultType() == TreeAttlistDeclAttributeDef.DEFAULT_TYPE_NULL)) {
367: sb.append("\"").append(attrDef.getDefaultValue())
368: .append("\""); // NOI18N
369: }
370: }
371:
372: sb.append(GREAT_THAN);
373: write(sb.toString());
374: }
375:
376: /**
377: * Write down the attribute if it was specified in document otherwise nothing.
378: */
379: public void writeAttribute(TreeAttribute attribute)
380: throws TreeException {
381: if (attribute.isSpecified() == false)
382: return;
383: write(createValueString(attribute.getQName(), attribute
384: .getNonNormalizedValue()));
385:
386: }
387:
388: /**
389: */
390: public void writeCDATASection(TreeCDATASection cdataSection)
391: throws TreeException {
392: String cdataData = cdataSection.getData();
393: String cdataString = MessageFormat.format(
394: "<![CDATA[{0}]]>", new Object[] { cdataData }); // NOI18N
395: write(cdataString);
396: }
397:
398: /**
399: */
400: public void writeCharacterReference(
401: TreeCharacterReference characterReference)
402: throws TreeException {
403: String refName = characterReference.getName();
404: String refString = MessageFormat.format("&{0};",
405: new Object[] { refName }); // NOI18N
406: write(refString);
407: }
408:
409: /**
410: */
411: public void writeComment(TreeComment comment)
412: throws TreeException {
413: String comName = comment.getData();
414: String comString = MessageFormat.format("<!--{0}-->",
415: new Object[] { comName }); // NOI18N
416: write(comString);
417: }
418:
419: /**
420: */
421: public void writeConditionalSection(
422: TreeConditionalSection conditionalSection)
423: throws TreeException {
424: if (conditionalSection.isInclude()) {
425: write("<![ INCLUDE [\n"); // NOI18N
426: writeObjectList(conditionalSection);
427: } else {
428: write("<![ IGNORE ["); // NOI18N
429: write(conditionalSection.getIgnoredContent());
430: }
431: write("]]>"); // NOI18N
432: }
433:
434: /**
435: */
436: public void writeDocumentFragment(
437: TreeDocumentFragment documentFragment)
438: throws TreeException {
439: StringBuffer sb = new StringBuffer();
440:
441: StringBuffer header = null;
442: if (documentFragment.getVersion() != null) {
443: if (header == null)
444: header = new StringBuffer();
445: header.append(
446: createValueString(XML_VERSION, documentFragment
447: .getVersion())).append(SPACE);
448: }
449: if (documentFragment.getEncoding() != null) {
450: if (header == null)
451: header = new StringBuffer();
452: header.append(createValueString(XML_ENCODING,
453: documentFragment.getEncoding()));
454: }
455: if (header != null) {
456: sb.append(XML_HEADER).append(header).append(PI_END);
457: }
458: write(sb.toString() + "\n\n"); // NOI18N
459:
460: indent -= indent_step;
461: writeObjectList(documentFragment);
462: }
463:
464: /**
465: */
466: public void writeDocument(TreeDocument document)
467: throws TreeException {
468: StringBuffer sb = new StringBuffer();
469:
470: StringBuffer header = null;
471: if (document.getVersion() != null) {
472: if (header == null)
473: header = new StringBuffer();
474: header.append(createValueString(XML_VERSION, document
475: .getVersion()));
476: }
477: if (document.getEncoding() != null) {
478: if (header == null)
479: header = new StringBuffer();
480: header.append(SPACE).append(
481: createValueString(XML_ENCODING, document
482: .getEncoding()));
483: }
484: if (document.getStandalone() != null) {
485: if (header == null)
486: header = new StringBuffer();
487: header.append(SPACE).append(
488: createValueString(XML_STANDALONE, document
489: .getStandalone()));
490: }
491: if (header != null) {
492: sb.append(XML_HEADER).append(header).append(PI_END);
493: }
494: write(sb.toString() + "\n"); // NOI18N
495:
496: indent -= indent_step;
497: writeObjectList(document);
498: }
499:
500: /**
501: */
502: public void writeDocumentType(TreeDocumentType documentType)
503: throws TreeException {
504: StringBuffer sb = new StringBuffer();
505:
506: sb.append(DOCTYPE_START).append(
507: documentType.getElementName());
508: if (documentType.getPublicId() != null) {
509: sb.append(SPACE).append(PUBLIC);
510: sb
511: .append(
512: createQuoteString(documentType
513: .getPublicId())).append(SPACE);
514: String systemId = documentType.getSystemId();
515: sb.append(createQuoteString(systemId == null ? ""
516: : systemId)); // NOI18N
517: } else if (documentType.getSystemId() != null) {
518: sb.append(SPACE).append(SYSTEM);
519: sb
520: .append(createQuoteString(documentType
521: .getSystemId()));
522: }
523: write(sb.toString());
524:
525: if (documentType.hasChildNodes()) {
526: write(" ["); // NOI18N
527:
528: //!!! use introspection to get internal DTD
529:
530: try {
531: if (documentType == null)
532: return;
533: Class klass = documentType.getClass();
534: Field field = klass
535: .getDeclaredField("internalDTDText"); // NOI18N
536: field.setAccessible(true);
537:
538: String internalDTDText = (String) field
539: .get(documentType);
540:
541: if (internalDTDText != null) {
542: write(internalDTDText);
543: } else {
544: // use tradition method instead (however it will resolve refs)
545: write("\n"); // NOI18N
546: writeObjectList(documentType);
547: }
548: } catch (RuntimeException ex) {
549: throw ex;
550: } catch (Exception ex) {
551: // use tradition method instead (however it will resolve refs)
552: write("\n"); // NOI18N
553: writeObjectList(documentType);
554: }
555:
556: write("]"); // NOI18N
557: }
558:
559: write(GREAT_THAN); // NOI18N
560: }
561:
562: /**
563: */
564: public void writeDTD(TreeDTD dtd) throws TreeException {
565: StringBuffer sb = new StringBuffer();
566:
567: StringBuffer header = null;
568: if (dtd.getVersion() != null) {
569: if (header == null)
570: header = new StringBuffer();
571: header
572: .append(
573: createValueString(XML_VERSION, dtd
574: .getVersion())).append(SPACE);
575: }
576: if (dtd.getEncoding() != null) {
577: if (header == null)
578: header = new StringBuffer();
579: header.append(createValueString(XML_ENCODING, dtd
580: .getEncoding()));
581: }
582: if (header != null) {
583: sb.append(XML_HEADER).append(header).append(PI_END);
584: }
585: write(sb.toString() + "\n\n"); // NOI18N
586:
587: indent -= indent_step;
588: writeObjectList(dtd);
589: }
590:
591: /**
592: */
593: public void writeElementDecl(TreeElementDecl elementDecl)
594: throws TreeException {
595: StringBuffer sb = new StringBuffer();
596: sb.append(ELEMENT_DECL_START).append(elementDecl.getName())
597: .append(SPACE);
598: sb.append(elementDecl.getContentType().toString());
599: sb.append(GREAT_THAN);
600: write(sb.toString());
601: }
602:
603: /**
604: */
605: public void writeElement(TreeElement element)
606: throws TreeException {
607: String elemName = element.getQName();
608: write("<" + elemName); // NOI18N
609:
610: Iterator it = element.getAttributes().iterator();
611: while (it.hasNext()) {
612: TreeAttribute attr = (TreeAttribute) it.next();
613: if (attr.isSpecified()) {
614: write(SPACE);
615: writeAttribute(attr);
616: }
617: }
618:
619: if (element.isEmpty()) {
620:
621: write("/>"); // NOI18N
622:
623: } else {
624: write(">"); // NOI18N
625:
626: // content
627: writeObjectList(element);
628:
629: // startIndent();
630: String endElemString = MessageFormat.format("</{0}>",
631: new Object[] { elemName }); // NOI18N
632: write(endElemString);
633: }
634: }
635:
636: /**
637: */
638: public void writeEntityDecl(TreeEntityDecl entityDecl)
639: throws TreeException {
640: String entParam = entityDecl.isParameter() ? "% " : ""; // NOI18N
641: String entName = entityDecl.getName();
642: String entType = ""; // NOI18N
643: switch (entityDecl.getType()) {
644: case TreeEntityDecl.TYPE_INTERNAL:
645: entType = "\"" + entityDecl.getInternalText() + "\""; // NOI18N
646: break;
647: case TreeEntityDecl.TYPE_EXTERNAL:
648: entType = createExternalIdString(entityDecl
649: .getPublicId(), entityDecl.getSystemId());
650: break;
651: case TreeEntityDecl.TYPE_UNPARSED:
652: entType = createExternalIdString(entityDecl
653: .getPublicId(), entityDecl.getSystemId())
654: + " NDATA " + entityDecl.getNotationName(); // NOI18N
655: break;
656: }
657: String entString = MessageFormat.format(
658: "<!ENTITY {0}{1} {2}>", new Object[] { entParam,
659: entName, entType }); // NOI18N
660: write(entString);
661: }
662:
663: /**
664: */
665: public void writeGeneralEntityReference(
666: TreeGeneralEntityReference generalEntityReference)
667: throws TreeException {
668: String refName = generalEntityReference.getName();
669: String refString = MessageFormat.format("&{0};",
670: new Object[] { refName }); // NOI18N
671: write(refString);
672: }
673:
674: /**
675: */
676: public void writeNotationDecl(TreeNotationDecl notationDecl)
677: throws TreeException {
678: String notName = notationDecl.getName();
679: String notSysId = notationDecl.getSystemId();
680: String notPubId = notationDecl.getPublicId();
681: String notExtId = createExternalIdString(notPubId, notSysId);
682: String notString = MessageFormat.format(
683: "<!NOTATION {0} {1}>", new Object[] { notName,
684: notExtId }); // NOI18N
685: write(notString);
686: }
687:
688: /**
689: */
690: public void writeParameterEntityReference(
691: TreeParameterEntityReference parameterEntityReference)
692: throws TreeException {
693: String refName = parameterEntityReference.getName();
694: String refString = MessageFormat.format("%{0};",
695: new Object[] { refName }); // NOI18N
696: write(refString);
697: }
698:
699: /**
700: */
701: public void writeProcessingInstruction(
702: TreeProcessingInstruction processingInstruction)
703: throws TreeException {
704: String piTarget = processingInstruction.getTarget();
705: String piData = processingInstruction.getData();
706: String piString = MessageFormat.format("<?{0} {1}?>",
707: new Object[] { piTarget, piData }); // NOI18N
708: write(piString);
709: }
710:
711: /**
712: */
713: public void writeText(TreeText text) throws TreeException {
714: String textString = text.getData();
715: write(textString);
716: }
717:
718: //
719: // itself
720: //
721:
722: private void write(String string) throws TreeException {
723: try {
724: writer.write(string);
725: } catch (IOException exc) {
726: throw new TreeException(exc);
727: }
728: }
729:
730: private void write(char ch) throws TreeException {
731: try {
732: writer.write(ch);
733: } catch (IOException exc) {
734: throw new TreeException(exc);
735: }
736: }
737:
738: private void startIndent() throws TreeException {
739: StringBuffer sb = new StringBuffer();
740: for (int i = 0; i < indent; i++) {
741: sb.append(' ');
742: }
743: try {
744: writer.write(sb.toString());
745: } catch (IOException exc) {
746: throw new TreeException(exc);
747: }
748: }
749:
750: private void endIndent() throws TreeException {
751: write("\n"); // NOI18N
752: }
753:
754: private void writeObjectList(TreeParentNode parentNode)
755: throws TreeException {
756: indent += indent_step;
757:
758: boolean notElementChild = (parentNode instanceof TreeElement) == false;
759: boolean documentChild = (parentNode instanceof TreeDocument) == true;
760:
761: Iterator it = parentNode.getChildNodes().iterator();
762: while (it.hasNext()) {
763: TreeNode node = (TreeNode) it.next();
764: // boolean isNotCharData = ( node instanceof TreeCharacterData ) == false;
765:
766: if (notElementChild) {
767: // if ( isNotCharData ) {
768: startIndent();
769: }
770:
771: writeNode(node);
772:
773: if (notElementChild) {
774: // if ( isNotCharData ) {
775: endIndent();
776: }
777: }
778: indent -= indent_step;
779: }
780:
781: /**
782: * Writes name value pair (attribute, encoding, standalone,...)
783: */
784: private String createValueString(String name, String value) {
785: String valueString = MessageFormat.format("{0}={1}",
786: new Object[] { name, createQuoteString(value) }); // NOI18N
787: return valueString;
788: }
789:
790: /**
791: * Autodetect quoting char giving highets priority to '"'.
792: */
793: private String createQuoteString(String value) {
794: Character quote = new Character(QUOTE);
795: if (value.indexOf(QUOTE) != -1) {
796: quote = new Character(APOSTROPHE);
797: }
798: return createQuoteString(value, quote);
799: }
800:
801: /**
802: */
803: private String createQuoteString(String value, Character quote) {
804: String valueString = MessageFormat.format("{1}{0}{1}",
805: new Object[] { value, quote }); // NOI18N
806: return valueString;
807: }
808:
809: /**
810: */
811: private String createExternalIdString(String publicId,
812: String systemId) {
813: String externId;
814: if (publicId == null) {
815: externId = MessageFormat.format("SYSTEM {0}",
816: new Object[] { createQuoteString(systemId) }); // NOI18N
817: } else if (systemId == null) {
818: externId = MessageFormat.format("PUBLIC {0}",
819: new Object[] { createQuoteString(publicId) }); // NOI18N
820: } else {
821: externId = MessageFormat.format("PUBLIC {0} {1}",
822: new Object[] { createQuoteString(publicId),
823: createQuoteString(systemId) }); // NOI18N
824: }
825: return externId;
826: }
827:
828: } // end: class TreeStreamWriter
829:
830: }
|