From a85355fd3e67e7a006e0f8b90c8142c0aefffce0 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Queru Date: Thu, 12 Nov 2009 18:45:52 -0800 Subject: eclair snapshot --- src/org/jheer/XMLWriter.java | 483 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 483 insertions(+) create mode 100644 src/org/jheer/XMLWriter.java diff --git a/src/org/jheer/XMLWriter.java b/src/org/jheer/XMLWriter.java new file mode 100644 index 0000000..cd811d9 --- /dev/null +++ b/src/org/jheer/XMLWriter.java @@ -0,0 +1,483 @@ +/** + * Copyright (c) 2004-2006 Regents of the University of California. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice and this list of conditions. + + 3. The name of the University may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + */ + +package org.jheer; + +//import java.io.PrintWriter; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; + +/** + * Utility class for writing XML files. This class provides convenience + * methods for creating XML documents, such as starting and ending + * tags, and adding content and comments. This class handles correct + * XML formatting and will properly escape text to ensure that the + * text remains valid XML. + * + *

To use this class, create a new instance with the desired + * [Print]FileWriter to write the XML to. Call the {@link #begin()} or + * {@link #begin(String, int)} method when ready to start outputting + * XML. Then use the provided methods to generate the XML file. + * Finally, call either the {@link #finish()} or {@link #finish(String)} + * methods to signal the completion of the file.

+ * + * @author jeffrey heer + * + * Modified to take a FileWriter and now throws IOException. + */ + +public class XMLWriter { + +// private PrintWriter m_out; + private FileWriter m_out; + private int m_bias = 0; + private int m_tab; + private ArrayList m_tagStack = new ArrayList(); + + /** + * Create a new XMLWriter. + * @param out the FileWriter to write the XML to + */ +// public XMLWriter(PrintWriter out) { + public XMLWriter(FileWriter out) { + this(out, 2); + } + + /** + * Create a new XMLWriter. + * @param out the FileWriter to write the XML to + * @param tabLength the number of spaces to use for each + * level of indentation in the XML file + */ +// public XMLWriter(PrintWriter out, int tabLength) { + public XMLWriter(FileWriter out, int tabLength) { + m_out = out; + m_tab = 2; + } + + /** + * Write unescaped text into the XML file. To write + * escaped text, use the {@link #content(String)} method instead. + * @param s the text to write. This String will not be escaped. + */ + public void write(String s) throws IOException { + m_out.write(s); + } + + /** + * Write unescaped text into the XML file, followed by + * a newline. To write escaped text, use the {@link #content(String)} + * method instead. + * @param s the text to write. This String will not be escaped. + */ + public void writeln(String s) throws IOException { + m_out.write(s); + m_out.write("\n"); + } + + /** + * Write a newline into the XML file. + */ + public void writeln() throws IOException { + m_out.write("\n"); + } + + /** + * Begin the XML document. This must be called before any other + * formatting methods. This method writes an XML header into + * the top of the output stream. + */ + public void begin() throws IOException { + m_out.write(""); + writeln(); + } + + /** + * Begin the XML document. This must be called before any other + * formatting methods. This method writes an XML header into + * the top of the output stream, plus additional header text + * provided by the client + * @param header header text to insert into the document + * @param bias the spacing bias to use for all subsequent indenting + */ + public void begin(String header, int bias) throws IOException { + begin(); + m_out.write(header); + m_bias = bias; + } + + /** + * Write a comment in the XML document. The comment will be written + * according to the current spacing and followed by a newline. + * @param comment the comment text + */ + public void comment(String comment) throws IOException { + spacing(); + m_out.write(""); + writeln(); + } + + /** + * Internal method for writing a tag with attributes. + * @param tag the tag name + * @param names the names of the attributes + * @param values the values of the attributes + * @param nattr the number of attributes + * @param close true to close the tag, false to leave it + * open and adjust the spacing + */ + protected void tag(String tag, String[] names, String[] values, + int nattr, boolean close) throws IOException + { + spacing(); + m_out.write('<'); + m_out.write(tag); + for ( int i=0; i'); + writeln(); + + if ( !close ) { + m_tagStack.add(tag); + } + } + + /** + * Write a closed tag with attributes. The tag will be followed by a + * newline. + * @param tag the tag name + * @param names the names of the attributes + * @param values the values of the attributes + * @param nattr the number of attributes + */ + public void tag(String tag, String[] names, String[] values, int nattr) throws IOException + { + tag(tag, names, values, nattr, true); + } + + /** + * Write a start tag with attributes. The tag will be followed by a + * newline, and the indentation level will be increased. + * @param tag the tag name + * @param names the names of the attributes + * @param values the values of the attributes + * @param nattr the number of attributes + */ + public void start(String tag, String[] names, String[] values, int nattr) throws IOException + { + tag(tag, names, values, nattr, false); + } + + /** + * Write a new attribut to an existing tag. The attribute will be followed by a newline. + * @param name the name of the attribute + * @param value the value of the attribute + */ + public void addAttribute(String name, String value) throws IOException { + spacing(); + m_out.write(name); + m_out.write('='); + m_out.write('\"'); + escapeString(value); + m_out.write('\"'); + writeln(); + } + + /** + * Internal method for writing a tag with a single attribute. + * @param tag the tag name + * @param name the name of the attribute + * @param value the value of the attribute + * @param close true to close the tag, false to leave it + * open and adjust the spacing + */ + protected void tag(String tag, String name, String value, boolean close) throws IOException { + spacing(); + m_out.write('<'); + m_out.write(tag); + m_out.write(' '); + m_out.write(name); + m_out.write('='); + m_out.write('\"'); + escapeString(value); + m_out.write('\"'); + if ( close ) m_out.write('/'); + m_out.write('>'); + writeln(); + + if ( !close ) { + m_tagStack.add(tag); + } + } + + /** + * Write a closed tag with one attribute. The tag will be followed by a + * newline. + * @param tag the tag name + * @param name the name of the attribute + * @param value the value of the attribute + */ + public void tag(String tag, String name, String value) throws IOException + { + tag(tag, name, value, true); + } + + /** + * Write a start tag with one attribute. The tag will be followed by a + * newline, and the indentation level will be increased. + * @param tag the tag name + * @param name the name of the attribute + * @param value the value of the attribute + */ + public void start(String tag, String name, String value) throws IOException + { + tag(tag, name, value, false); + } + + /** + * Internal method for writing a tag with attributes. + * @param tag the tag name + * @param names the names of the attributes + * @param values the values of the attributes + * @param nattr the number of attributes + * @param close true to close the tag, false to leave it + * open and adjust the spacing + */ + protected void tag(String tag, ArrayList names, ArrayList values, + int nattr, boolean close) throws IOException + { + spacing(); + m_out.write('<'); + m_out.write(tag); + for ( int i=0; i'); + writeln(); + + if ( !close ) { + m_tagStack.add(tag); + } + } + + /** + * Write a closed tag with attributes. The tag will be followed by a + * newline. + * @param tag the tag name + * @param names the names of the attributes + * @param values the values of the attributes + * @param nattr the number of attributes + */ + public void tag(String tag, ArrayList names, ArrayList values, int nattr) throws IOException + { + tag(tag, names, values, nattr, true); + } + + /** + * Write a start tag with attributes. The tag will be followed by a + * newline, and the indentation level will be increased. + * @param tag the tag name + * @param names the names of the attributes + * @param values the values of the attributes + * @param nattr the number of attributes + */ + public void start(String tag, ArrayList names, ArrayList values, int nattr) throws IOException + { + tag(tag, names, values, nattr, false); + } + + /** + * Write a start tag without attributes. The tag will be followed by a + * newline, and the indentation level will be increased. + * @param tag the tag name + */ + public void start(String tag) throws IOException { + tag(tag, (String[])null, null, 0, false); + } + + /** + * Close the most recently opened tag. The tag will be followed by a + * newline, and the indentation level will be decreased. + */ + public void end() throws IOException { + String tag = (String)m_tagStack.remove(m_tagStack.size()-1); + spacing(); + m_out.write('<'); + m_out.write('/'); + m_out.write(tag); + m_out.write('>'); + writeln(); + } + + /** + * Write a new content tag with a single attribute, consisting of an + * open tag, content text, and a closing tag, all on one line. + * @param tag the tag name + * @param name the name of the attribute + * @param value the value of the attribute, this text will be escaped + * @param content the text content, this text will be escaped + */ + public void contentTag(String tag, String name, String value, String content) throws IOException + { + spacing(); + m_out.write('<'); m_out.write(tag); m_out.write(' '); + m_out.write(name); m_out.write('='); + m_out.write('\"'); escapeString(value); m_out.write('\"'); + m_out.write('>'); + escapeString(content); + m_out.write('<'); m_out.write('/'); m_out.write(tag); m_out.write('>'); + writeln(); + } + + /** + * Write a new content tag with no attributes, consisting of an + * open tag, content text, and a closing tag, all on one line. + * @param tag the tag name + * @param content the text content, this text will be escaped + */ + public void contentTag(String tag, String content) throws IOException { + spacing(); + m_out.write('<'); m_out.write(tag); m_out.write('>'); + escapeString(content); + m_out.write('<'); m_out.write('/'); m_out.write(tag); m_out.write('>'); + writeln(); + } + + /** + * Write content text. + * @param content the content text, this text will be escaped + */ + public void content(String content) throws IOException { + escapeString(content); + } + + /** + * Finish the XML document. + */ + public void finish() throws IOException { + m_bias = 0; + m_out.flush(); + } + + /** + * Finish the XML document, writing the given footer text at the + * end of the document. + * @param footer the footer text, this will not be escaped + */ + public void finish(String footer) throws IOException { + m_bias = 0; + m_out.write(footer); + m_out.flush(); + } + + /** + * Write the current spacing (determined by the indentation level) + * into the document. This method is used by many of the other + * formatting methods, and so should only need to be called in + * the case of custom text writing outside the mechanisms + * provided by this class. + */ + public void spacing() throws IOException { + int len = m_bias + m_tagStack.size() * m_tab; + for ( int i=0; i', '"', '\'', '&' }; + private static final String[] VALID = + { "<", ">", """, "'", "&" }; + + /** + * Escape a string such that it is safe to use in an XML document. + * @param str the string to escape + */ + protected void escapeString(String str) throws IOException { + if ( str == null ) { + m_out.write("null"); + return; + } + + int len = str.length(); + for (int i = 0; i < len; ++i) { + char c = str.charAt(i); + + if ( (c < LOWER_RANGE && c != VALID_CHARS[0] && + c != VALID_CHARS[1] && c != VALID_CHARS[2]) + || (c > UPPER_RANGE) ) + { + // character out of range, escape with character value + m_out.write("&#"); + m_out.write(Integer.toString(c)); + m_out.write(';'); + } else { + boolean valid = true; + // check for invalid characters (e.g., "<", "&", etc) + for (int j=INVALID.length-1; j >= 0; --j ) + { + if ( INVALID[j] == c) { + valid = false; + m_out.write(VALID[j]); + break; + } + } + // if character is valid, don't escape + if (valid) { + m_out.write(c); + } + } + } + } + +} // end of class XMLWriter + -- cgit v1.2.3 -- cgit v1.2.3