001: package com.flexive.war.webdav.catalina;
002:
003: import org.w3c.dom.*;
004:
005: import java.io.OutputStreamWriter;
006: import java.io.PrintWriter;
007: import java.io.UnsupportedEncodingException;
008: import java.io.Writer;
009:
010: /**
011: * Catalina sources cloned for packaging issues to the flexive source tree.
012: * Refactored to JDK 1.5 compatibility.
013: * Licensed under the Apache License, Version 2.0
014: * <p/>
015: * A sample DOM writer. This sample program illustrates how to
016: * traverse a DOM tree in order to print a document that is parsed.
017: *
018: * @author Markus Plesser (markus.plesser@flexive.com), UCS - unique computing solutions gmbh (http://www.ucs.at)
019: */
020: public class DOMWriter {
021:
022: //
023: // Data
024: //
025:
026: /**
027: * Default Encoding
028: */
029: private static String PRINTWRITER_ENCODING = "UTF8";
030:
031: private static String MIME2JAVA_ENCODINGS[] = { "Default", "UTF-8",
032: "US-ASCII", "ISO-8859-1", "ISO-8859-2", "ISO-8859-3",
033: "ISO-8859-4", "ISO-8859-5", "ISO-8859-6", "ISO-8859-7",
034: "ISO-8859-8", "ISO-8859-9", "ISO-2022-JP", "SHIFT_JIS",
035: "EUC-JP", "GB2312", "BIG5", "EUC-KR", "ISO-2022-KR",
036: "KOI8-R", "EBCDIC-CP-US", "EBCDIC-CP-CA", "EBCDIC-CP-NL",
037: "EBCDIC-CP-DK", "EBCDIC-CP-NO", "EBCDIC-CP-FI",
038: "EBCDIC-CP-SE", "EBCDIC-CP-IT", "EBCDIC-CP-ES",
039: "EBCDIC-CP-GB", "EBCDIC-CP-FR", "EBCDIC-CP-AR1",
040: "EBCDIC-CP-HE", "EBCDIC-CP-CH", "EBCDIC-CP-ROECE",
041: "EBCDIC-CP-YU", "EBCDIC-CP-IS", "EBCDIC-CP-AR2", "UTF-16" };
042:
043: /**
044: * Output qualified names
045: */
046: private boolean qualifiedNames = true;
047:
048: /**
049: * Print writer.
050: */
051: protected PrintWriter out;
052:
053: /**
054: * Canonical output.
055: */
056: protected boolean canonical;
057:
058: public DOMWriter(String encoding, boolean canonical)
059: throws UnsupportedEncodingException {
060: out = new PrintWriter(new OutputStreamWriter(System.out,
061: encoding));
062: this .canonical = canonical;
063: } // <init>(String,boolean)
064:
065: //
066: // Constructors
067: //
068:
069: /**
070: * Default constructor.
071: */
072: public DOMWriter(boolean canonical)
073: throws UnsupportedEncodingException {
074: this (getWriterEncoding(), canonical);
075: }
076:
077: public DOMWriter(Writer writer, boolean canonical) {
078: out = new PrintWriter(writer);
079: this .canonical = canonical;
080: }
081:
082: public boolean getQualifiedNames() {
083: return this .qualifiedNames;
084: }
085:
086: public void setQualifiedNames(boolean qualifiedNames) {
087: this .qualifiedNames = qualifiedNames;
088: }
089:
090: public static String getWriterEncoding() {
091: return (PRINTWRITER_ENCODING);
092: }// getWriterEncoding
093:
094: public static void setWriterEncoding(String encoding) {
095: if (encoding.equalsIgnoreCase("DEFAULT"))
096: PRINTWRITER_ENCODING = "UTF8";
097: else if (encoding.equalsIgnoreCase("UTF-16"))
098: PRINTWRITER_ENCODING = "Unicode";
099: else
100: PRINTWRITER_ENCODING = MIME2Java.convert(encoding);
101: }// setWriterEncoding
102:
103: public static boolean isValidJavaEncoding(String encoding) {
104: for (String aMIME2JAVA_ENCODINGS : MIME2JAVA_ENCODINGS)
105: if (encoding.equals(aMIME2JAVA_ENCODINGS))
106: return (true);
107:
108: return (false);
109: }// isValidJavaEncoding
110:
111: /**
112: * Prints the specified node, recursively.
113: */
114: public void print(Node node) {
115:
116: // is there anything to do?
117: if (node == null) {
118: return;
119: }
120:
121: int type = node.getNodeType();
122: switch (type) {
123: // print document
124: case Node.DOCUMENT_NODE: {
125: if (!canonical) {
126: String Encoding = getWriterEncoding();
127: if (Encoding.equalsIgnoreCase("DEFAULT"))
128: Encoding = "UTF-8";
129: else if (Encoding.equalsIgnoreCase("Unicode"))
130: Encoding = "UTF-16";
131: else
132: Encoding = MIME2Java.reverse(Encoding);
133:
134: out.println("<?xml version=\"1.0\" encoding=\""
135: + Encoding + "\"?>");
136: }
137: print(((Document) node).getDocumentElement());
138: out.flush();
139: break;
140: }
141:
142: // print element with attributes
143: case Node.ELEMENT_NODE: {
144: out.print('<');
145: if (this .qualifiedNames) {
146: out.print(node.getNodeName());
147: } else {
148: out.print(node.getLocalName());
149: }
150: Attr attrs[] = sortAttributes(node.getAttributes());
151: for (Attr attr : attrs) {
152: out.print(' ');
153: if (this .qualifiedNames) {
154: out.print(attr.getNodeName());
155: } else {
156: out.print(attr.getLocalName());
157: }
158:
159: out.print("=\"");
160: out.print(normalize(attr.getNodeValue()));
161: out.print('"');
162: }
163: out.print('>');
164: NodeList children = node.getChildNodes();
165: if (children != null) {
166: int len = children.getLength();
167: for (int i = 0; i < len; i++) {
168: print(children.item(i));
169: }
170: }
171: break;
172: }
173:
174: // handle entity reference nodes
175: case Node.ENTITY_REFERENCE_NODE: {
176: if (canonical) {
177: NodeList children = node.getChildNodes();
178: if (children != null) {
179: int len = children.getLength();
180: for (int i = 0; i < len; i++) {
181: print(children.item(i));
182: }
183: }
184: } else {
185: out.print('&');
186: if (this .qualifiedNames) {
187: out.print(node.getNodeName());
188: } else {
189: out.print(node.getLocalName());
190: }
191: out.print(';');
192: }
193: break;
194: }
195:
196: // print cdata sections
197: case Node.CDATA_SECTION_NODE: {
198: if (canonical) {
199: out.print(normalize(node.getNodeValue()));
200: } else {
201: out.print("<![CDATA[");
202: out.print(node.getNodeValue());
203: out.print("]]>");
204: }
205: break;
206: }
207:
208: // print text
209: case Node.TEXT_NODE: {
210: out.print(normalize(node.getNodeValue()));
211: break;
212: }
213:
214: // print processing instruction
215: case Node.PROCESSING_INSTRUCTION_NODE: {
216: out.print("<?");
217: if (this .qualifiedNames) {
218: out.print(node.getNodeName());
219: } else {
220: out.print(node.getLocalName());
221: }
222:
223: String data = node.getNodeValue();
224: if (data != null && data.length() > 0) {
225: out.print(' ');
226: out.print(data);
227: }
228: out.print("?>");
229: break;
230: }
231: }
232:
233: if (type == Node.ELEMENT_NODE) {
234: out.print("</");
235: if (this .qualifiedNames) {
236: out.print(node.getNodeName());
237: } else {
238: out.print(node.getLocalName());
239: }
240: out.print('>');
241: }
242:
243: out.flush();
244:
245: } // print(Node)
246:
247: /**
248: * Returns a sorted list of attributes.
249: */
250: protected Attr[] sortAttributes(NamedNodeMap attrs) {
251:
252: int len = (attrs != null) ? attrs.getLength() : 0;
253: Attr array[] = new Attr[len];
254: assert attrs != null;
255: for (int i = 0; i < len; i++) {
256: array[i] = (Attr) attrs.item(i);
257: }
258: for (int i = 0; i < len - 1; i++) {
259: String name;
260: if (this .qualifiedNames) {
261: name = array[i].getNodeName();
262: } else {
263: name = array[i].getLocalName();
264: }
265: int index = i;
266: for (int j = i + 1; j < len; j++) {
267: String curName;
268: if (this .qualifiedNames) {
269: curName = array[j].getNodeName();
270: } else {
271: curName = array[j].getLocalName();
272: }
273: if (curName.compareTo(name) < 0) {
274: name = curName;
275: index = j;
276: }
277: }
278: if (index != i) {
279: Attr temp = array[i];
280: array[i] = array[index];
281: array[index] = temp;
282: }
283: }
284:
285: return (array);
286:
287: } // sortAttributes(NamedNodeMap):Attr[]
288:
289: /**
290: * Normalizes the given string.
291: */
292: protected String normalize(String s) {
293: StringBuffer str = new StringBuffer();
294:
295: int len = (s != null) ? s.length() : 0;
296: for (int i = 0; i < len; i++) {
297: char ch = s.charAt(i);
298: switch (ch) {
299: case '<': {
300: str.append("<");
301: break;
302: }
303: case '>': {
304: str.append(">");
305: break;
306: }
307: case '&': {
308: str.append("&");
309: break;
310: }
311: case '"': {
312: str.append(""");
313: break;
314: }
315: case '\r':
316: case '\n': {
317: if (canonical) {
318: str.append("&#");
319: str.append(Integer.toString(ch));
320: str.append(';');
321: break;
322: }
323: // else, default append char
324: }
325: default: {
326: str.append(ch);
327: }
328: }
329: }
330:
331: return (str.toString());
332:
333: } // normalize(String):String
334:
335: }
|