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