001: /*
002: * The contents of this file are subject to the terms of the Common Development
003: * and Distribution License (the License). You may not use this file except in
004: * compliance with the License.
005: *
006: * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
007: * or http://www.netbeans.org/cddl.txt.
008: *
009: * When distributing Covered Code, include this CDDL Header Notice in each file
010: * and include the License file at http://www.netbeans.org/cddl.txt.
011: * If applicable, add the following below the CDDL Header, with the fields
012: * enclosed by brackets [] replaced by your own identifying information:
013: * "Portions Copyrighted [year] [name of copyright owner]"
014: *
015: * The Original Software is NetBeans. The Initial Developer of the Original
016: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
017: * Microsystems, Inc. All Rights Reserved.
018: */
019:
020: /*
021: *
022: * Copyright 2005 Sun Microsystems, Inc.
023: *
024: * Licensed under the Apache License, Version 2.0 (the "License");
025: * you may not use this file except in compliance with the License.
026: * You may obtain a copy of the License at
027: *
028: * http://www.apache.org/licenses/LICENSE-2.0
029: *
030: * Unless required by applicable law or agreed to in writing, software
031: * distributed under the License is distributed on an "AS IS" BASIS,
032: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
033: * See the License for the specific language governing permissions and
034: * limitations under the License.
035: *
036: */
037: package org.netbeans.modules.jdbcwizard.builder.xsd;
038:
039: import java.io.PrintWriter;
040: import java.io.UnsupportedEncodingException;
041: import java.io.Writer;
042: import org.w3c.dom.Attr;
043: import org.w3c.dom.NamedNodeMap;
044: import org.w3c.dom.Node;
045: import org.w3c.dom.NodeList;
046:
047: /**
048: * A sample DOM writer. This class traverses a DOM tree to print an xml document.
049: *
050: * @author
051: */
052:
053: public class DOMWriter {
054:
055: /** Default Encoding */
056: private static final String PRINTWRITER_ENCODING = "UTF-8";
057:
058: private static final String TAB = " ";
059:
060: /** Canonical output. */
061: protected boolean canonical;
062:
063: /** Print writer. */
064: protected PrintWriter out;
065:
066: /**
067: * @param w Writer
068: * @param canonical canonical
069: * @exception UnsupportedEncodingException Unsupported encoding exception
070: * @todo Document this constructor
071: */
072: public DOMWriter(final Writer w, final boolean canonical)
073: throws UnsupportedEncodingException {
074: this .out = new PrintWriter(w);
075: this .canonical = canonical;
076: }
077:
078: /**
079: * Returns the Writer Encoding
080: *
081: * @return Encoding used
082: */
083: public static String getWriterEncoding() {
084: return DOMWriter.PRINTWRITER_ENCODING;
085: }
086:
087: // getWriterEncoding
088:
089: /**
090: * @param node Node
091: * @todo Document this method
092: */
093: public void print(final String indent, final Node node) {
094: this .print(indent, node, true);
095: }
096:
097: /**
098: * Prints the specified node, recursively.
099: *
100: * @param node Node
101: * @param prettyprint Pretty print the result
102: */
103: public void print(final String indent, final Node node,
104: final boolean prettyprint) {
105: // is there anything to do?
106: if (node == null) {
107: return;
108: }
109:
110: final int type = node.getNodeType();
111: switch (type) {
112: // print document
113: case Node.DOCUMENT_NODE: {
114: if (!this .canonical) {
115: String encoding = DOMWriter.getWriterEncoding();
116: if (encoding.equalsIgnoreCase("DEFAULT")) {
117: encoding = "UTF-8";
118: } else if (encoding.equalsIgnoreCase("Unicode")) {
119: encoding = "UTF-16";
120: } else {
121: // encoding = MIME2Java.reverse(encoding);
122: }
123:
124: this .out.println("<?xml version=\"1.0\" encoding=\""
125: + encoding + "\"?>");
126: }
127: final NodeList children = node.getChildNodes();
128: for (int iChild = 0; iChild < children.getLength(); iChild++) {
129: this .print(indent, children.item(iChild));
130: }
131: this .out.flush();
132: break;
133: }
134: // print element with attributes
135: case Node.ELEMENT_NODE: {
136: this .out.print(indent + '<');
137: this .out.print(node.getNodeName());
138: final Attr attrs[] = this .sortAttributes(node
139: .getAttributes());
140: for (int i = 0; i < attrs.length; i++) {
141: final Attr attr = attrs[i];
142: this .out.print(' ');
143: this .out.print(attr.getNodeName());
144: this .out.print("=\"");
145: this .out.print(this .normalize(attr.getNodeValue()));
146: this .out.print('"');
147: }
148: this .out.print('>');
149: final NodeList children = node.getChildNodes();
150: if (children != null) {
151: final int len = children.getLength();
152: for (int i = 0; i < len; i++) {
153: final Node child = children.item(i);
154: if (child.getNodeType() != Node.TEXT_NODE) {
155: this .out.println();
156: }
157: this
158: .print(indent + DOMWriter.TAB, children
159: .item(i));
160: }
161: }
162: break;
163: }
164: // handle entity reference nodes
165: case Node.ENTITY_REFERENCE_NODE: {
166: if (this .canonical) {
167: final NodeList children = node.getChildNodes();
168: if (children != null) {
169: final int len = children.getLength();
170: for (int i = 0; i < len; i++) {
171: this .print(indent, children.item(i));
172: }
173: }
174: } else {
175: this .out.print('&');
176: this .out.print(node.getNodeName());
177: this .out.print(';');
178: }
179: break;
180: }
181: // print cdata sections
182: case Node.CDATA_SECTION_NODE: {
183: if (this .canonical) {
184: this .out.print(this .normalize(node.getNodeValue()));
185: } else {
186: this .out.print("<![CDATA[");
187: this .out.print(node.getNodeValue());
188: this .out.print("]]>");
189: }
190: break;
191: }
192: // print text
193: case Node.TEXT_NODE: {
194: this .out.print(this .normalize(node.getNodeValue()));
195: break;
196: }
197: // print processing instruction
198: case Node.PROCESSING_INSTRUCTION_NODE: {
199: this .out.print("<?");
200: this .out.print(node.getNodeName());
201: final String data = node.getNodeValue();
202: if (data != null && data.length() > 0) {
203: this .out.print(' ');
204: this .out.print(data);
205: }
206: this .out.println("?>");
207: break;
208: }
209: }
210:
211: if (type == Node.ELEMENT_NODE) {
212: if (this .containsOnlyTextNode(node)) {
213: this .out.print("</");
214: } else {
215: this .out.println();
216: this .out.print(indent + "</");
217: }
218: this .out.print(node.getNodeName());
219: this .out.print('>');
220: // if (prettyprint) {
221: // out.println();
222: // }
223: }
224:
225: this .out.flush();
226:
227: }
228:
229: /**
230: * Normalizes the given string.
231: *
232: * @param s String to be normalized
233: * @return normalized string
234: */
235: protected String normalize(final String s) {
236: final StringBuffer str = new StringBuffer();
237: final int len = s != null ? s.length() : 0;
238: for (int i = 0; i < len; i++) {
239: final char ch = s.charAt(i);
240: switch (ch) {
241: case '<': {
242: str.append("<");
243: break;
244: }
245: case '>': {
246: str.append(">");
247: break;
248: }
249: case '&': {
250: str.append("&");
251: break;
252: }
253: case '"': {
254: str.append(""");
255: break;
256: }
257: case '\r':
258: case '\n': {
259: if (this .canonical) {
260: str.append("&#");
261: str.append(Integer.toString(ch));
262: str.append(';');
263: } else {
264: // else, default append char
265: str.append(ch);
266: }
267: break;
268: }
269: default: {
270: str.append(ch);
271: }
272: }
273: }
274: return str.toString();
275: }
276:
277: /**
278: * Returns a sorted list of attributes.
279: *
280: * @param attrs Map of named nodes
281: * @return Array of sorted list of attributes
282: */
283: protected Attr[] sortAttributes(final NamedNodeMap attrs) {
284: final int len = attrs != null ? attrs.getLength() : 0;
285: final Attr array[] = new Attr[len];
286: for (int i = 0; i < len; i++) {
287: array[i] = (Attr) attrs.item(i);
288: }
289:
290: for (int i = 0; i < len - 1; i++) {
291: String name = array[i].getNodeName();
292: int index = i;
293: for (int j = i + 1; j < len; j++) {
294: final String curName = array[j].getNodeName();
295: if (curName.compareTo(name) < 0) {
296: name = curName;
297: index = j;
298: }
299: }
300:
301: if (index != i) {
302: final Attr temp = array[i];
303: array[i] = array[index];
304: array[index] = temp;
305: }
306: }
307:
308: return array;
309: }
310:
311: private boolean containsOnlyTextNode(final Node node) {
312: final NodeList children = node.getChildNodes();
313: for (int i = 0; i < children.getLength(); i++) {
314: if (children.item(i).getNodeType() != Node.TEXT_NODE) {
315: return false;
316: }
317: }
318: return true;
319: }
320:
321: }
|