• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2009-2010 jMonkeyEngine
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17  *   may be used to endorse or promote products derived from this software
18  *   without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 package com.jme3.export.xml;
34 
35 import java.io.*;
36 import java.nio.charset.Charset;
37 import org.w3c.dom.*;
38 
39 /**
40  * The DOMSerializer was based primarily off the DOMSerializer.java class from the
41  * "Java and XML" 3rd Edition book by Brett McLaughlin, and Justin Edelson. Some
42  * modifications were made to support formatting of elements and attributes.
43  *
44  * @author Brett McLaughlin, Justin Edelson - Original creation for "Java and XML" book.
45  * @author Doug Daniels (dougnukem) - adjustments for XML formatting
46  * @version $Revision: 4207 $, $Date: 2009-03-29 11:19:16 -0400 (Sun, 29 Mar 2009) $
47  */
48 public class DOMSerializer {
49 
50     /** The encoding to use for output (default is UTF-8) */
51     private Charset encoding = Charset.forName("utf-8");
52 
53     /** The amount of indentation to use (default is 4 spaces). */
54     private int indent = 4;
55 
56     /** The line separator to use (default is the based on the current system settings). */
57     private String lineSeparator = System.getProperty("line.separator", "\n");
58 
escape(Writer writer, String s)59     private void escape(Writer writer, String s) throws IOException {
60         if (s == null) { return; }
61         for (int i = 0, len = s.length(); i < len; i++) {
62             char c = s.charAt(i);
63             switch (c) {
64             case '<':
65                 writer.write("&lt;");
66                 break;
67             case '>':
68                 writer.write("&gt;");
69                 break;
70             case '&':
71                 writer.write("&amp;");
72                 break;
73             case '\r':
74                 writer.write("&#xD;");
75                 break;
76             default:
77                 writer.write(c);
78             }
79         }
80     }
81 
82     /**
83      * Serialize {@code doc} to {@code out}
84      *
85      * @param doc the document to serialize.
86      * @param file the file to serialize to.
87      * @throws IOException
88      */
serialize(Document doc, File file)89     public void serialize(Document doc, File file) throws IOException {
90         serialize(doc, new FileOutputStream(file));
91     }
92 
93     /**
94      * Serialize {@code doc} to {@code out}
95      *
96      * @param doc the document to serialize.
97      * @param out the stream to serialize to.
98      * @throws IOException
99      */
serialize(Document doc, OutputStream out)100     public void serialize(Document doc, OutputStream out) throws IOException {
101         Writer writer = new OutputStreamWriter(out, encoding);
102         write(doc, writer, 0);
103         writer.flush();
104     }
105 
106     /**
107      * Set the encoding used by this serializer.
108      *
109      * @param encoding the encoding to use, passing in {@code null} results in the
110      *  default encoding (UTF-8) being set.
111      * @throws IllegalCharsetNameException if the given charset name is illegal.
112      * @throws UnsupportedCharsetException if the given charset is not supported by the
113      *  current JVM.
114      */
setEncoding(String encoding)115     public void setEncoding(String encoding) {
116         this.encoding = Charset.forName(encoding);
117     }
118 
119     /**
120      * Set the number of spaces to use for indentation.
121      * <p>
122      * The default is to use 4 spaces.
123      *
124      * @param indent the number of spaces to use for indentation, values less than or
125      *  equal to zero result in no indentation being used.
126      */
setIndent(int indent)127     public void setIndent(int indent) {
128         this.indent = indent >= 0 ? indent : 0;
129     }
130 
131     /**
132      * Set the line separator that will be used when serializing documents.
133      * <p>
134      * If this is not called then the serializer uses a default based on the
135      * {@code line.separator} system property.
136      *
137      * @param lineSeparator the line separator to set.
138      */
setLineSeparator(String lineSeparator)139     public void setLineSeparator(String lineSeparator) {
140         this.lineSeparator = lineSeparator;
141     }
142 
write(Node node, Writer writer, int depth)143     private void write(Node node, Writer writer, int depth) throws IOException {
144         switch (node.getNodeType()) {
145         case Node.DOCUMENT_NODE:
146             writeDocument((Document) node, writer);
147             break;
148         case Node.ELEMENT_NODE:
149             writeElement((Element) node, writer, depth);
150             break;
151         case Node.TEXT_NODE:
152             escape(writer, node.getNodeValue());
153             break;
154         case Node.CDATA_SECTION_NODE:
155             writer.write("<![CDATA[");
156             escape(writer, node.getNodeValue());
157             writer.write("]]>");
158             break;
159         case Node.COMMENT_NODE:
160             for (int i = 0; i < depth; ++i) { writer.append(' '); }
161             writer.append("<!-- ").append(node.getNodeValue()).append(" -->").append(lineSeparator);
162             break;
163         case Node.PROCESSING_INSTRUCTION_NODE:
164             String n = node.getNodeName();
165             String v = node.getNodeValue();
166             for (int i = 0; i < depth; ++i) { writer.append(' '); }
167             writer.append("<?").append(n).append(' ').append(v).append("?>").append(lineSeparator);
168             break;
169         case Node.ENTITY_REFERENCE_NODE:
170             writer.append('&').append(node.getNodeName()).append(';');
171             break;
172         case Node.DOCUMENT_TYPE_NODE:
173             writeDocumentType((DocumentType) node, writer, depth);
174             break;
175         }
176     }
177 
writeDocument(Document document, Writer writer)178     private void writeDocument(Document document, Writer writer) throws IOException {
179         String v = document.getXmlVersion();
180 
181         writer.append("<?xml ");
182         writer.append(" version='").append(v == null ? "1.0" : v).append("'");
183         writer.append(" encoding='").append(encoding.name()).append("'");
184         if (document.getXmlStandalone()) {
185             writer.append(" standalone='yes'");
186         }
187         writer.append("?>").append(lineSeparator);
188 
189         NodeList nodes = document.getChildNodes();
190         for (int i = 0, imax = nodes.getLength(); i < imax; ++i) {
191             write(nodes.item(i), writer, 0);
192         }
193     }
194 
writeDocumentType(DocumentType docType, Writer writer, int depth)195     private void writeDocumentType(DocumentType docType, Writer writer, int depth) throws IOException {
196         String publicId = docType.getPublicId();
197         String internalSubset = docType.getInternalSubset();
198 
199         for (int i = 0; i < depth; ++i) { writer.append(' '); }
200         writer.append("<!DOCTYPE ").append(docType.getName());
201         if (publicId != null) {
202             writer.append(" PUBLIC '").append(publicId).append("' ");
203         } else {
204             writer.write(" SYSTEM ");
205         }
206         writer.append("'").append(docType.getSystemId()).append("'");
207         if (internalSubset != null) {
208             writer.append(" [").append(internalSubset).append("]");
209         }
210         writer.append('>').append(lineSeparator);
211     }
212 
writeElement(Element element, Writer writer, int depth)213     private void writeElement(Element element, Writer writer, int depth) throws IOException {
214         for (int i = 0; i < depth; ++i) { writer.append(' '); }
215         writer.append('<').append(element.getTagName());
216         NamedNodeMap attrs = element.getAttributes();
217         for (int i = 0, imax = attrs.getLength(); i < imax; ++i) {
218             Attr attr = (Attr) attrs.item(i);
219             writer.append(' ').append(attr.getName()).append("='").append(attr.getValue()).append("'");
220         }
221         NodeList nodes = element.getChildNodes();
222         if (nodes.getLength() == 0) {
223             // no children, so just close off the element and return
224             writer.append("/>").append(lineSeparator);
225             return;
226         }
227         writer.append('>').append(lineSeparator);
228         for (int i = 0, imax = nodes.getLength(); i < imax; ++i) {
229             Node n = nodes.item(i);
230             if (n.getNodeType() == Node.ATTRIBUTE_NODE) { continue; }
231             write(n, writer, depth + indent);
232         }
233         for (int i = 0; i < depth; ++i) { writer.append(' '); }
234         writer.append("</").append(element.getTagName()).append('>').append(lineSeparator);
235     }
236 
237 }
238