001: /* XMLWriter.java NanoXML/Java
002: *
003: * $Revision: 1.17 $
004: * $Date: 2005/01/05 17:20:04 $
005: * $Name: $
006: *
007: * This file is part of NanoXML 2 for Java.
008: * Copyright (C) 2000-2002 Marc De Scheemaecker, All Rights Reserved.
009: *
010: * This software is provided 'as-is', without any express or implied warranty.
011: * In no event will the authors be held liable for any damages arising from the
012: * use of this software.
013: *
014: * Permission is granted to anyone to use this software for any purpose,
015: * including commercial applications, and to alter it and redistribute it
016: * freely, subject to the following restrictions:
017: *
018: * 1. The origin of this software must not be misrepresented; you must not
019: * claim that you wrote the original software. If you use this software in
020: * a product, an acknowledgment in the product documentation would be
021: * appreciated but is not required.
022: *
023: * 2. Altered source versions must be plainly marked as such, and must not be
024: * misrepresented as being the original software.
025: *
026: * 3. This notice may not be removed or altered from any source distribution.
027: */
028:
029: package net.n3.nanoxml;
030:
031: import java.io.IOException;
032: import java.io.OutputStream;
033: import java.io.PrintWriter;
034: import java.io.Writer;
035: import java.util.Enumeration;
036: import java.util.Vector;
037:
038: /**
039: * An XMLWriter writes XML data to a stream.
040: *
041: * @see net.n3.nanoxml.IXMLElement
042: * @see java.io.Writer
043: *
044: * @author Marc De Scheemaecker
045: * @version $Name: $, $Revision: 1.17 $
046: */
047: public class XMLWriter {
048:
049: /**
050: * Where to write the output to.
051: */
052: private PrintWriter writer;
053:
054: /**
055: * Creates a new XML writer.
056: *
057: * @param writer where to write the output to.
058: */
059: public XMLWriter(Writer writer) {
060: if (writer instanceof PrintWriter) {
061: this .writer = (PrintWriter) writer;
062: } else {
063: this .writer = new PrintWriter(writer);
064: }
065: }
066:
067: /**
068: * Creates a new XML writer.
069: *
070: * @param stream where to write the output to.
071: */
072: public XMLWriter(OutputStream stream) {
073: this .writer = new PrintWriter(stream);
074: }
075:
076: /**
077: * Cleans up the object when it's destroyed.
078: */
079: protected void finalize() throws Throwable {
080: this .writer = null;
081: super .finalize();
082: }
083:
084: /**
085: * Writes an XML element.
086: *
087: * @param xml the non-null XML element to write.
088: */
089: public void write(IXMLElement xml) throws IOException {
090: this .write(xml, false, 0, true);
091: }
092:
093: /**
094: * Writes an XML element.
095: *
096: * @param xml the non-null XML element to write.
097: * @param prettyPrint if spaces need to be inserted to make the output more
098: * readable
099: */
100: public void write(IXMLElement xml, boolean prettyPrint)
101: throws IOException {
102: this .write(xml, prettyPrint, 0, true);
103: }
104:
105: /**
106: * Writes an XML element.
107: *
108: * @param xml the non-null XML element to write.
109: * @param prettyPrint if spaces need to be inserted to make the output more
110: * readable
111: * @param indent how many spaces to indent the element.
112: */
113: public void write(IXMLElement xml, boolean prettyPrint, int indent)
114: throws IOException {
115: this .write(xml, prettyPrint, indent, true);
116: }
117:
118: /**
119: * Writes an XML element.
120: *
121: * @param xml the non-null XML element to write.
122: * @param prettyPrint if spaces need to be inserted to make the output more
123: * readable
124: * @param indent how many spaces to indent the element.
125: */
126: public void write(IXMLElement xml,
127: boolean prettyPrint,
128: int indent,
129: boolean collapseEmptyElements)
130: throws IOException
131: {
132: if (prettyPrint) {
133: for (int i = 0; i < indent; i++) {
134: this .writer.print(' ');
135: }
136: }
137:
138: if (xml.getName() == null) {
139: if (xml.getContent() != null) {
140: if (prettyPrint) {
141: this .writeEncoded(xml.getContent().trim());
142: writer.println();
143: } else {
144: this .writeEncoded(xml.getContent());
145: }
146: }
147: } else {
148: this .writer.print('<');
149: this .writer.print(xml.getFullName());
150: Vector nsprefixes = new Vector();
151:
152: if (xml.getNamespace() != null) {
153: if (xml.getName().equals(xml.getFullName())) {
154: this .writer.print(" xmlns=\"" + xml.getNamespace() + '"');
155: } else {
156: String prefix = xml.getFullName();
157: prefix = prefix.substring(0, prefix.indexOf(':'));
158: nsprefixes.addElement(prefix);
159: this .writer.print(" xmlns:" + prefix);
160: this .writer.print("=\"" + xml.getNamespace() + "\"");
161: }
162: }
163:
164: Enumeration enum = xml.enumerateAttributeNames();
165:
166: while (enum.hasMoreElements()) {
167: String key = (String) enum.nextElement();
168: int index = key.indexOf(':');
169:
170: if (index >= 0) {
171: String namespace = xml.getAttributeNamespace(key);
172:
173: if (namespace != null) {
174: String prefix = key.substring(0, index);
175:
176: if (! nsprefixes.contains(prefix)) {
177: this .writer.print(" xmlns:" + prefix);
178: this .writer.print("=\"" + namespace + '"');
179: nsprefixes.addElement(prefix);
180: }
181: }
182: }
183: }
184:
185: enum = xml.enumerateAttributeNames();
186:
187: while (enum.hasMoreElements()) {
188: String key = (String) enum.nextElement();
189: String value = xml.getAttribute(key, null);
190: this .writer.print(" " + key + "=\"");
191: this .writeEncoded(value);
192: this .writer.print('"');
193: }
194:
195: if ((xml.getContent() != null)
196: && (xml.getContent().length() > 0)) {
197: writer.print('>');
198: this .writeEncoded(xml.getContent());
199: writer.print("</" + xml.getFullName() + '>');
200:
201: if (prettyPrint) {
202: writer.println();
203: }
204: } else if (xml.hasChildren() || (! collapseEmptyElements)) {
205: writer.print('>');
206:
207: if (prettyPrint) {
208: writer.println();
209: }
210:
211: enum = xml.enumerateChildren();
212:
213: while (enum.hasMoreElements()) {
214: IXMLElement child = (IXMLElement) enum.nextElement();
215: this .write(child, prettyPrint, indent + 4,
216: collapseEmptyElements);
217: }
218:
219: if (prettyPrint) {
220: for (int i = 0; i < indent; i++) {
221: this .writer.print(' ');
222: }
223: }
224:
225: this .writer.print("</" + xml.getFullName() + ">");
226:
227: if (prettyPrint) {
228: writer.println();
229: }
230: } else {
231: this .writer.print("/>");
232:
233: if (prettyPrint) {
234: writer.println();
235: }
236: }
237: }
238:
239: this .writer.flush();
240: }
241:
242: /**
243: * Writes a string encoding reserved characters.
244: *
245: * @param str the string to write.
246: */
247: private void writeEncoded(String str) {
248: for (int i = 0; i < str.length(); i++) {
249: char c = str.charAt(i);
250:
251: switch (c) {
252: case 0x0A:
253: this .writer.print(c);
254: break;
255:
256: case '<':
257: this .writer.print("<");
258: break;
259:
260: case '>':
261: this .writer.print(">");
262: break;
263:
264: case '&':
265: this .writer.print("&");
266: break;
267:
268: case '\'':
269: this .writer.print("'");
270: break;
271:
272: case '"':
273: this .writer.print(""");
274: break;
275:
276: default:
277: if ((c < ' ') || (c > 0x7E)) {
278: this .writer.print("&#x");
279: this .writer.print(Integer.toString(c, 16));
280: this .writer.print(';');
281: } else {
282: this.writer.print(c);
283: }
284: }
285: }
286: }
287:
288: }
|