001: /*
002: * The Apache Software License, Version 1.1
003: *
004: *
005: * Copyright (c) 1999, 2000 The Apache Software Foundation. All rights
006: * reserved.
007: *
008: * Redistribution and use in source and binary forms, with or without
009: * modification, are permitted provided that the following conditions
010: * are met:
011: *
012: * 1. Redistributions of source code must retain the above copyright
013: * notice, this list of conditions and the following disclaimer.
014: *
015: * 2. Redistributions in binary conform must reproduce the above copyright
016: * notice, this list of conditions and the following disclaimer in
017: * the documentation and/or other materials provided with the
018: * distribution.
019: *
020: * 3. The end-user documentation included with the redistribution,
021: * if any, must include the following acknowledgment:
022: * "This product includes software developed by the
023: * Apache Software Foundation (http://www.apache.org/)."
024: * Alternately, this acknowledgment may appear in the software itself,
025: * if and wherever such third-party acknowledgments normally appear.
026: *
027: * 4. The names "Xerces" and "Apache Software Foundation" must
028: * not be used to endorse or promote products derived from this
029: * software without prior written permission. For written
030: * permission, please contact apache@apache.org.
031: *
032: * 5. Products derived from this software may not be called "Apache",
033: * nor may "Apache" appear in their name, without prior written
034: * permission of the Apache Software Foundation.
035: *
036: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
037: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
038: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
039: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
040: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
041: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
042: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
043: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
044: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
045: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
046: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
047: * SUCH DAMAGE.
048: * ====================================================================
049: *
050: * This software consists of voluntary contributions made by many
051: * individuals on behalf of the Apache Software Foundation and was
052: * originally based on software copyright (c) 1999, International
053: * Business Machines, Inc., http://www.apache.org. For more
054: * information on the Apache Software Foundation, please see
055: * <http://www.apache.org/>.
056: */
057:
058: package org.conform.util;
059:
060: import java.io.PrintWriter;
061: import java.io.Writer;
062: import java.io.UnsupportedEncodingException;
063:
064: import org.w3c.dom.Attr;
065: import org.w3c.dom.NamedNodeMap;
066: import org.w3c.dom.Node;
067: import org.w3c.dom.NodeList;
068:
069: /**
070: * A sample DOM writer. This sample program illustrates how to
071: * traverse a DOM tree in order to print a document that is parsed.
072: *
073: * @version $Id: DOMWriter.java 435 2005-04-29 13:36:50Z hengels $
074: * @version ORIGINAL - DOMWriter.java,v 1.8 2000/09/19 17:15:47 jeffreyr
075: */
076: public class DOMWriter {
077:
078: //
079: // Constants
080: //
081:
082: //
083: // Data
084: //
085:
086: /** Default Encoding */
087: private static String PRINTWRITER_ENCODING = "UTF8";
088:
089: private static String MIME2JAVA_ENCODINGS[] = { "Default", "UTF-8",
090: "US-ASCII", "ISO-8859-1", "ISO-8859-2", "ISO-8859-3",
091: "ISO-8859-4", "ISO-8859-5", "ISO-8859-6", "ISO-8859-7",
092: "ISO-8859-8", "ISO-8859-9", "ISO-2022-JP", "SHIFT_JIS",
093: "EUC-JP", "GB2312", "BIG5", "EUC-KR", "ISO-2022-KR",
094: "KOI8-R", "EBCDIC-CP-US", "EBCDIC-CP-CA", "EBCDIC-CP-NL",
095: "EBCDIC-CP-DK", "EBCDIC-CP-NO", "EBCDIC-CP-FI",
096: "EBCDIC-CP-SE", "EBCDIC-CP-IT", "EBCDIC-CP-ES",
097: "EBCDIC-CP-GB", "EBCDIC-CP-FR", "EBCDIC-CP-AR1",
098: "EBCDIC-CP-HE", "EBCDIC-CP-CH", "EBCDIC-CP-ROECE",
099: "EBCDIC-CP-YU", "EBCDIC-CP-IS", "EBCDIC-CP-AR2", "UTF-16" };
100:
101: /** Print writer. */
102: protected PrintWriter out;
103:
104: /** Canonical output. */
105: protected boolean canonical;
106:
107: public DOMWriter(Writer w, boolean canonical)
108: throws UnsupportedEncodingException {
109: out = new PrintWriter(w);
110: this .canonical = canonical;
111: } // <init>(String,boolean)
112:
113: //
114: // Constructors
115: //
116:
117: public static String getWriterEncoding() {
118: return (PRINTWRITER_ENCODING);
119: }// getWriterEncoding
120:
121: public void print(Node node) {
122: print(node, true);
123: }
124:
125: /** Prints the specified node, recursively. */
126: public void print(Node node, boolean prettyprint) {
127:
128: // is there anything to do?
129: if (node == null) {
130: return;
131: }
132:
133: int type = node.getNodeType();
134: switch (type) {
135: // print document
136: case Node.DOCUMENT_NODE: {
137: if (!canonical) {
138: String Encoding = this .getWriterEncoding();
139: if (Encoding.equalsIgnoreCase("DEFAULT"))
140: Encoding = "UTF-8";
141: else if (Encoding.equalsIgnoreCase("Unicode"))
142: Encoding = "UTF-16";
143: else
144: Encoding = MIME2Java.reverse(Encoding);
145:
146: out.println("<?xml version=\"1.0\" encoding=\""
147: + Encoding + "\"?>");
148: }
149: //print(((Document)node).getDocumentElement());
150:
151: NodeList children = node.getChildNodes();
152: for (int iChild = 0; iChild < children.getLength(); iChild++) {
153: print(children.item(iChild));
154: }
155: out.flush();
156: break;
157: }
158:
159: // print element with attributes
160: case Node.ELEMENT_NODE: {
161: out.print('<');
162: out.print(node.getNodeName());
163: Attr attrs[] = sortAttributes(node.getAttributes());
164: for (int i = 0; i < attrs.length; i++) {
165: Attr attr = attrs[i];
166: out.print(' ');
167: out.print(attr.getNodeName());
168: out.print("=\"");
169: out.print(normalize(attr.getNodeValue()));
170: out.print('"');
171: }
172: out.print('>');
173: NodeList children = node.getChildNodes();
174: if (children != null) {
175: int len = children.getLength();
176: for (int i = 0; i < len; i++) {
177: print(children.item(i));
178: }
179: }
180: break;
181: }
182:
183: // handle entity reference nodes
184: case Node.ENTITY_REFERENCE_NODE: {
185: if (canonical) {
186: NodeList children = node.getChildNodes();
187: if (children != null) {
188: int len = children.getLength();
189: for (int i = 0; i < len; i++) {
190: print(children.item(i));
191: }
192: }
193: } else {
194: out.print('&');
195: out.print(node.getNodeName());
196: out.print(';');
197: }
198: break;
199: }
200:
201: // print cdata sections
202: case Node.CDATA_SECTION_NODE: {
203: if (canonical) {
204: out.print(normalize(node.getNodeValue()));
205: } else {
206: out.print("<![CDATA[");
207: out.print(node.getNodeValue());
208: out.print("]]>");
209: }
210: break;
211: }
212:
213: // print text
214: case Node.TEXT_NODE: {
215: out.print(normalize(node.getNodeValue()));
216: break;
217: }
218:
219: // print processing instruction
220: case Node.PROCESSING_INSTRUCTION_NODE: {
221: out.print("<?");
222: out.print(node.getNodeName());
223: String data = node.getNodeValue();
224: if (data != null && data.length() > 0) {
225: out.print(' ');
226: out.print(data);
227: }
228: out.println("?>");
229: break;
230: }
231: }
232:
233: if (type == Node.ELEMENT_NODE) {
234: out.print("</");
235: out.print(node.getNodeName());
236: out.print('>');
237: if (prettyprint)
238: out.println();
239: }
240:
241: out.flush();
242:
243: } // print(Node)
244:
245: /** Returns a sorted list of attributes. */
246: protected Attr[] sortAttributes(NamedNodeMap attrs) {
247:
248: int len = (attrs != null) ? attrs.getLength() : 0;
249: Attr array[] = new Attr[len];
250: for (int i = 0; i < len; i++) {
251: array[i] = (Attr) attrs.item(i);
252: }
253: for (int i = 0; i < len - 1; i++) {
254: String name = array[i].getNodeName();
255: int index = i;
256: for (int j = i + 1; j < len; j++) {
257: String curName = array[j].getNodeName();
258: if (curName.compareTo(name) < 0) {
259: name = curName;
260: index = j;
261: }
262: }
263: if (index != i) {
264: Attr temp = array[i];
265: array[i] = array[index];
266: array[index] = temp;
267: }
268: }
269:
270: return (array);
271:
272: } // sortAttributes(NamedNodeMap):Attr[]
273:
274: /** Normalizes the given string. */
275: protected String normalize(String s) {
276: StringBuffer str = new StringBuffer();
277:
278: int len = (s != null) ? s.length() : 0;
279: for (int i = 0; i < len; i++) {
280: char ch = s.charAt(i);
281: switch (ch) {
282: case '<': {
283: str.append("<");
284: break;
285: }
286: case '>': {
287: str.append(">");
288: break;
289: }
290: case '&': {
291: str.append("&");
292: break;
293: }
294: case '"': {
295: str.append(""");
296: break;
297: }
298: case '\r':
299: case '\n': {
300: if (canonical) {
301: str.append("&#");
302: str.append(Integer.toString(ch));
303: str.append(';');
304: break;
305: }
306: // else, default append char
307: }
308: default: {
309: str.append(ch);
310: }
311: }
312: }
313:
314: return (str.toString());
315:
316: } // normalize(String):String
317:
318: }
|