XMLWriter.java revision 6934ac109bf80019d70ea684c203f12ca58c365e
16934ac109bf80019d70ea684c203f12ca58c365emike ritter/** 26934ac109bf80019d70ea684c203f12ca58c365emike ritter * Copyright (c) 2004-2006 Regents of the University of California. 36934ac109bf80019d70ea684c203f12ca58c365emike ritter All rights reserved. 46934ac109bf80019d70ea684c203f12ca58c365emike ritter 56934ac109bf80019d70ea684c203f12ca58c365emike ritter Redistribution and use in source and binary forms, with or without 66934ac109bf80019d70ea684c203f12ca58c365emike ritter modification, are permitted provided that the following conditions 76934ac109bf80019d70ea684c203f12ca58c365emike ritter are met: 86934ac109bf80019d70ea684c203f12ca58c365emike ritter 96934ac109bf80019d70ea684c203f12ca58c365emike ritter 1. Redistributions of source code must retain the above copyright 106934ac109bf80019d70ea684c203f12ca58c365emike ritter notice, this list of conditions and the following disclaimer. 116934ac109bf80019d70ea684c203f12ca58c365emike ritter 126934ac109bf80019d70ea684c203f12ca58c365emike ritter 2. Redistributions in binary form must reproduce the above copyright 136934ac109bf80019d70ea684c203f12ca58c365emike ritter notice and this list of conditions. 146934ac109bf80019d70ea684c203f12ca58c365emike ritter 156934ac109bf80019d70ea684c203f12ca58c365emike ritter 3. The name of the University may not be used to endorse or promote products 166934ac109bf80019d70ea684c203f12ca58c365emike ritter derived from this software without specific prior written permission. 176934ac109bf80019d70ea684c203f12ca58c365emike ritter 186934ac109bf80019d70ea684c203f12ca58c365emike ritter THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 196934ac109bf80019d70ea684c203f12ca58c365emike ritter ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 206934ac109bf80019d70ea684c203f12ca58c365emike ritter IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 216934ac109bf80019d70ea684c203f12ca58c365emike ritter ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 226934ac109bf80019d70ea684c203f12ca58c365emike ritter FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 236934ac109bf80019d70ea684c203f12ca58c365emike ritter DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 246934ac109bf80019d70ea684c203f12ca58c365emike ritter OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 256934ac109bf80019d70ea684c203f12ca58c365emike ritter HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 266934ac109bf80019d70ea684c203f12ca58c365emike ritter LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 276934ac109bf80019d70ea684c203f12ca58c365emike ritter OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 286934ac109bf80019d70ea684c203f12ca58c365emike ritter SUCH DAMAGE. 296934ac109bf80019d70ea684c203f12ca58c365emike ritter */ 306934ac109bf80019d70ea684c203f12ca58c365emike ritter 316934ac109bf80019d70ea684c203f12ca58c365emike ritterpackage org.jheer; 326934ac109bf80019d70ea684c203f12ca58c365emike ritter 336934ac109bf80019d70ea684c203f12ca58c365emike ritter//import java.io.PrintWriter; 346934ac109bf80019d70ea684c203f12ca58c365emike ritterimport java.io.FileWriter; 356934ac109bf80019d70ea684c203f12ca58c365emike ritterimport java.io.IOException; 366934ac109bf80019d70ea684c203f12ca58c365emike ritterimport java.util.ArrayList; 376934ac109bf80019d70ea684c203f12ca58c365emike ritter 386934ac109bf80019d70ea684c203f12ca58c365emike ritter/** 396934ac109bf80019d70ea684c203f12ca58c365emike ritter * Utility class for writing XML files. This class provides convenience 406934ac109bf80019d70ea684c203f12ca58c365emike ritter * methods for creating XML documents, such as starting and ending 416934ac109bf80019d70ea684c203f12ca58c365emike ritter * tags, and adding content and comments. This class handles correct 426934ac109bf80019d70ea684c203f12ca58c365emike ritter * XML formatting and will properly escape text to ensure that the 436934ac109bf80019d70ea684c203f12ca58c365emike ritter * text remains valid XML. 446934ac109bf80019d70ea684c203f12ca58c365emike ritter * 456934ac109bf80019d70ea684c203f12ca58c365emike ritter * <p>To use this class, create a new instance with the desired 466934ac109bf80019d70ea684c203f12ca58c365emike ritter * [Print]FileWriter to write the XML to. Call the {@link #begin()} or 476934ac109bf80019d70ea684c203f12ca58c365emike ritter * {@link #begin(String, int)} method when ready to start outputting 486934ac109bf80019d70ea684c203f12ca58c365emike ritter * XML. Then use the provided methods to generate the XML file. 496934ac109bf80019d70ea684c203f12ca58c365emike ritter * Finally, call either the {@link #finish()} or {@link #finish(String)} 506934ac109bf80019d70ea684c203f12ca58c365emike ritter * methods to signal the completion of the file.</p> 516934ac109bf80019d70ea684c203f12ca58c365emike ritter * 526934ac109bf80019d70ea684c203f12ca58c365emike ritter * @author <a href="http://jheer.org">jeffrey heer</a> 536934ac109bf80019d70ea684c203f12ca58c365emike ritter * 546934ac109bf80019d70ea684c203f12ca58c365emike ritter * Modified to take a FileWriter and now throws IOException. 556934ac109bf80019d70ea684c203f12ca58c365emike ritter */ 566934ac109bf80019d70ea684c203f12ca58c365emike ritter 576934ac109bf80019d70ea684c203f12ca58c365emike ritterpublic class XMLWriter { 586934ac109bf80019d70ea684c203f12ca58c365emike ritter 596934ac109bf80019d70ea684c203f12ca58c365emike ritter// private PrintWriter m_out; 606934ac109bf80019d70ea684c203f12ca58c365emike ritter private FileWriter m_out; 616934ac109bf80019d70ea684c203f12ca58c365emike ritter private int m_bias = 0; 626934ac109bf80019d70ea684c203f12ca58c365emike ritter private int m_tab; 636934ac109bf80019d70ea684c203f12ca58c365emike ritter private ArrayList m_tagStack = new ArrayList(); 646934ac109bf80019d70ea684c203f12ca58c365emike ritter 656934ac109bf80019d70ea684c203f12ca58c365emike ritter /** 666934ac109bf80019d70ea684c203f12ca58c365emike ritter * Create a new XMLWriter. 676934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param out the FileWriter to write the XML to 686934ac109bf80019d70ea684c203f12ca58c365emike ritter */ 696934ac109bf80019d70ea684c203f12ca58c365emike ritter// public XMLWriter(PrintWriter out) { 706934ac109bf80019d70ea684c203f12ca58c365emike ritter public XMLWriter(FileWriter out) { 716934ac109bf80019d70ea684c203f12ca58c365emike ritter this(out, 2); 726934ac109bf80019d70ea684c203f12ca58c365emike ritter } 736934ac109bf80019d70ea684c203f12ca58c365emike ritter 746934ac109bf80019d70ea684c203f12ca58c365emike ritter /** 756934ac109bf80019d70ea684c203f12ca58c365emike ritter * Create a new XMLWriter. 766934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param out the FileWriter to write the XML to 776934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param tabLength the number of spaces to use for each 786934ac109bf80019d70ea684c203f12ca58c365emike ritter * level of indentation in the XML file 796934ac109bf80019d70ea684c203f12ca58c365emike ritter */ 806934ac109bf80019d70ea684c203f12ca58c365emike ritter// public XMLWriter(PrintWriter out, int tabLength) { 816934ac109bf80019d70ea684c203f12ca58c365emike ritter public XMLWriter(FileWriter out, int tabLength) { 826934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out = out; 836934ac109bf80019d70ea684c203f12ca58c365emike ritter m_tab = 2; 846934ac109bf80019d70ea684c203f12ca58c365emike ritter } 856934ac109bf80019d70ea684c203f12ca58c365emike ritter 866934ac109bf80019d70ea684c203f12ca58c365emike ritter /** 876934ac109bf80019d70ea684c203f12ca58c365emike ritter * Write <em>unescaped</em> text into the XML file. To write 886934ac109bf80019d70ea684c203f12ca58c365emike ritter * escaped text, use the {@link #content(String)} method instead. 896934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param s the text to write. This String will not be escaped. 906934ac109bf80019d70ea684c203f12ca58c365emike ritter */ 916934ac109bf80019d70ea684c203f12ca58c365emike ritter public void write(String s) throws IOException { 926934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write(s); 936934ac109bf80019d70ea684c203f12ca58c365emike ritter } 946934ac109bf80019d70ea684c203f12ca58c365emike ritter 956934ac109bf80019d70ea684c203f12ca58c365emike ritter /** 966934ac109bf80019d70ea684c203f12ca58c365emike ritter * Write <em>unescaped</em> text into the XML file, followed by 976934ac109bf80019d70ea684c203f12ca58c365emike ritter * a newline. To write escaped text, use the {@link #content(String)} 986934ac109bf80019d70ea684c203f12ca58c365emike ritter * method instead. 996934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param s the text to write. This String will not be escaped. 1006934ac109bf80019d70ea684c203f12ca58c365emike ritter */ 1016934ac109bf80019d70ea684c203f12ca58c365emike ritter public void writeln(String s) throws IOException { 1026934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write(s); 1036934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write("\n"); 1046934ac109bf80019d70ea684c203f12ca58c365emike ritter } 1056934ac109bf80019d70ea684c203f12ca58c365emike ritter 1066934ac109bf80019d70ea684c203f12ca58c365emike ritter /** 1076934ac109bf80019d70ea684c203f12ca58c365emike ritter * Write a newline into the XML file. 1086934ac109bf80019d70ea684c203f12ca58c365emike ritter */ 1096934ac109bf80019d70ea684c203f12ca58c365emike ritter public void writeln() throws IOException { 1106934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write("\n"); 1116934ac109bf80019d70ea684c203f12ca58c365emike ritter } 1126934ac109bf80019d70ea684c203f12ca58c365emike ritter 1136934ac109bf80019d70ea684c203f12ca58c365emike ritter /** 1146934ac109bf80019d70ea684c203f12ca58c365emike ritter * Begin the XML document. This must be called before any other 1156934ac109bf80019d70ea684c203f12ca58c365emike ritter * formatting methods. This method writes an XML header into 1166934ac109bf80019d70ea684c203f12ca58c365emike ritter * the top of the output stream. 1176934ac109bf80019d70ea684c203f12ca58c365emike ritter */ 1186934ac109bf80019d70ea684c203f12ca58c365emike ritter public void begin() throws IOException { 1196934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); 1206934ac109bf80019d70ea684c203f12ca58c365emike ritter writeln(); 1216934ac109bf80019d70ea684c203f12ca58c365emike ritter } 1226934ac109bf80019d70ea684c203f12ca58c365emike ritter 1236934ac109bf80019d70ea684c203f12ca58c365emike ritter /** 1246934ac109bf80019d70ea684c203f12ca58c365emike ritter * Begin the XML document. This must be called before any other 1256934ac109bf80019d70ea684c203f12ca58c365emike ritter * formatting methods. This method writes an XML header into 1266934ac109bf80019d70ea684c203f12ca58c365emike ritter * the top of the output stream, plus additional header text 1276934ac109bf80019d70ea684c203f12ca58c365emike ritter * provided by the client 1286934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param header header text to insert into the document 1296934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param bias the spacing bias to use for all subsequent indenting 1306934ac109bf80019d70ea684c203f12ca58c365emike ritter */ 1316934ac109bf80019d70ea684c203f12ca58c365emike ritter public void begin(String header, int bias) throws IOException { 1326934ac109bf80019d70ea684c203f12ca58c365emike ritter begin(); 1336934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write(header); 1346934ac109bf80019d70ea684c203f12ca58c365emike ritter m_bias = bias; 1356934ac109bf80019d70ea684c203f12ca58c365emike ritter } 1366934ac109bf80019d70ea684c203f12ca58c365emike ritter 1376934ac109bf80019d70ea684c203f12ca58c365emike ritter /** 1386934ac109bf80019d70ea684c203f12ca58c365emike ritter * Write a comment in the XML document. The comment will be written 1396934ac109bf80019d70ea684c203f12ca58c365emike ritter * according to the current spacing and followed by a newline. 1406934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param comment the comment text 1416934ac109bf80019d70ea684c203f12ca58c365emike ritter */ 1426934ac109bf80019d70ea684c203f12ca58c365emike ritter public void comment(String comment) throws IOException { 1436934ac109bf80019d70ea684c203f12ca58c365emike ritter spacing(); 1446934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write("<!-- "); 1456934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write(comment); 1466934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write(" -->"); 1476934ac109bf80019d70ea684c203f12ca58c365emike ritter writeln(); 1486934ac109bf80019d70ea684c203f12ca58c365emike ritter } 1496934ac109bf80019d70ea684c203f12ca58c365emike ritter 1506934ac109bf80019d70ea684c203f12ca58c365emike ritter /** 1516934ac109bf80019d70ea684c203f12ca58c365emike ritter * Internal method for writing a tag with attributes. 1526934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param tag the tag name 1536934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param names the names of the attributes 1546934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param values the values of the attributes 1556934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param nattr the number of attributes 1566934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param close true to close the tag, false to leave it 1576934ac109bf80019d70ea684c203f12ca58c365emike ritter * open and adjust the spacing 1586934ac109bf80019d70ea684c203f12ca58c365emike ritter */ 1596934ac109bf80019d70ea684c203f12ca58c365emike ritter protected void tag(String tag, String[] names, String[] values, 1606934ac109bf80019d70ea684c203f12ca58c365emike ritter int nattr, boolean close) throws IOException 1616934ac109bf80019d70ea684c203f12ca58c365emike ritter { 1626934ac109bf80019d70ea684c203f12ca58c365emike ritter spacing(); 1636934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write('<'); 1646934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write(tag); 1656934ac109bf80019d70ea684c203f12ca58c365emike ritter for ( int i=0; i<nattr; ++i ) { 1666934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write(' '); 1676934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write(names[i]); 1686934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write('='); 1696934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write('\"'); 1706934ac109bf80019d70ea684c203f12ca58c365emike ritter escapeString(values[i]); 1716934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write('\"'); 1726934ac109bf80019d70ea684c203f12ca58c365emike ritter } 1736934ac109bf80019d70ea684c203f12ca58c365emike ritter if ( close ) m_out.write('/'); 1746934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write('>'); 1756934ac109bf80019d70ea684c203f12ca58c365emike ritter writeln(); 1766934ac109bf80019d70ea684c203f12ca58c365emike ritter 1776934ac109bf80019d70ea684c203f12ca58c365emike ritter if ( !close ) { 1786934ac109bf80019d70ea684c203f12ca58c365emike ritter m_tagStack.add(tag); 1796934ac109bf80019d70ea684c203f12ca58c365emike ritter } 1806934ac109bf80019d70ea684c203f12ca58c365emike ritter } 1816934ac109bf80019d70ea684c203f12ca58c365emike ritter 1826934ac109bf80019d70ea684c203f12ca58c365emike ritter /** 1836934ac109bf80019d70ea684c203f12ca58c365emike ritter * Write a closed tag with attributes. The tag will be followed by a 1846934ac109bf80019d70ea684c203f12ca58c365emike ritter * newline. 1856934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param tag the tag name 1866934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param names the names of the attributes 1876934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param values the values of the attributes 1886934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param nattr the number of attributes 1896934ac109bf80019d70ea684c203f12ca58c365emike ritter */ 1906934ac109bf80019d70ea684c203f12ca58c365emike ritter public void tag(String tag, String[] names, String[] values, int nattr) throws IOException 1916934ac109bf80019d70ea684c203f12ca58c365emike ritter { 1926934ac109bf80019d70ea684c203f12ca58c365emike ritter tag(tag, names, values, nattr, true); 1936934ac109bf80019d70ea684c203f12ca58c365emike ritter } 1946934ac109bf80019d70ea684c203f12ca58c365emike ritter 1956934ac109bf80019d70ea684c203f12ca58c365emike ritter /** 1966934ac109bf80019d70ea684c203f12ca58c365emike ritter * Write a start tag with attributes. The tag will be followed by a 1976934ac109bf80019d70ea684c203f12ca58c365emike ritter * newline, and the indentation level will be increased. 1986934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param tag the tag name 1996934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param names the names of the attributes 2006934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param values the values of the attributes 2016934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param nattr the number of attributes 2026934ac109bf80019d70ea684c203f12ca58c365emike ritter */ 2036934ac109bf80019d70ea684c203f12ca58c365emike ritter public void start(String tag, String[] names, String[] values, int nattr) throws IOException 2046934ac109bf80019d70ea684c203f12ca58c365emike ritter { 2056934ac109bf80019d70ea684c203f12ca58c365emike ritter tag(tag, names, values, nattr, false); 2066934ac109bf80019d70ea684c203f12ca58c365emike ritter } 2076934ac109bf80019d70ea684c203f12ca58c365emike ritter 2086934ac109bf80019d70ea684c203f12ca58c365emike ritter /** 2096934ac109bf80019d70ea684c203f12ca58c365emike ritter * Write a new attribut to an existing tag. The attribute will be followed by a newline. 2106934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param name the name of the attribute 2116934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param value the value of the attribute 2126934ac109bf80019d70ea684c203f12ca58c365emike ritter */ 2136934ac109bf80019d70ea684c203f12ca58c365emike ritter public void addAttribute(String name, String value) throws IOException { 2146934ac109bf80019d70ea684c203f12ca58c365emike ritter spacing(); 2156934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write(name); 2166934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write('='); 2176934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write('\"'); 2186934ac109bf80019d70ea684c203f12ca58c365emike ritter escapeString(value); 2196934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write('\"'); 2206934ac109bf80019d70ea684c203f12ca58c365emike ritter writeln(); 2216934ac109bf80019d70ea684c203f12ca58c365emike ritter } 2226934ac109bf80019d70ea684c203f12ca58c365emike ritter 2236934ac109bf80019d70ea684c203f12ca58c365emike ritter /** 2246934ac109bf80019d70ea684c203f12ca58c365emike ritter * Internal method for writing a tag with a single attribute. 2256934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param tag the tag name 2266934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param name the name of the attribute 2276934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param value the value of the attribute 2286934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param close true to close the tag, false to leave it 2296934ac109bf80019d70ea684c203f12ca58c365emike ritter * open and adjust the spacing 2306934ac109bf80019d70ea684c203f12ca58c365emike ritter */ 2316934ac109bf80019d70ea684c203f12ca58c365emike ritter protected void tag(String tag, String name, String value, boolean close) throws IOException { 2326934ac109bf80019d70ea684c203f12ca58c365emike ritter spacing(); 2336934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write('<'); 2346934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write(tag); 2356934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write(' '); 2366934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write(name); 2376934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write('='); 2386934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write('\"'); 2396934ac109bf80019d70ea684c203f12ca58c365emike ritter escapeString(value); 2406934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write('\"'); 2416934ac109bf80019d70ea684c203f12ca58c365emike ritter if ( close ) m_out.write('/'); 2426934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write('>'); 2436934ac109bf80019d70ea684c203f12ca58c365emike ritter writeln(); 2446934ac109bf80019d70ea684c203f12ca58c365emike ritter 2456934ac109bf80019d70ea684c203f12ca58c365emike ritter if ( !close ) { 2466934ac109bf80019d70ea684c203f12ca58c365emike ritter m_tagStack.add(tag); 2476934ac109bf80019d70ea684c203f12ca58c365emike ritter } 2486934ac109bf80019d70ea684c203f12ca58c365emike ritter } 2496934ac109bf80019d70ea684c203f12ca58c365emike ritter 2506934ac109bf80019d70ea684c203f12ca58c365emike ritter /** 2516934ac109bf80019d70ea684c203f12ca58c365emike ritter * Write a closed tag with one attribute. The tag will be followed by a 2526934ac109bf80019d70ea684c203f12ca58c365emike ritter * newline. 2536934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param tag the tag name 2546934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param name the name of the attribute 2556934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param value the value of the attribute 2566934ac109bf80019d70ea684c203f12ca58c365emike ritter */ 2576934ac109bf80019d70ea684c203f12ca58c365emike ritter public void tag(String tag, String name, String value) throws IOException 2586934ac109bf80019d70ea684c203f12ca58c365emike ritter { 2596934ac109bf80019d70ea684c203f12ca58c365emike ritter tag(tag, name, value, true); 2606934ac109bf80019d70ea684c203f12ca58c365emike ritter } 2616934ac109bf80019d70ea684c203f12ca58c365emike ritter 2626934ac109bf80019d70ea684c203f12ca58c365emike ritter /** 2636934ac109bf80019d70ea684c203f12ca58c365emike ritter * Write a start tag with one attribute. The tag will be followed by a 2646934ac109bf80019d70ea684c203f12ca58c365emike ritter * newline, and the indentation level will be increased. 2656934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param tag the tag name 2666934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param name the name of the attribute 2676934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param value the value of the attribute 2686934ac109bf80019d70ea684c203f12ca58c365emike ritter */ 2696934ac109bf80019d70ea684c203f12ca58c365emike ritter public void start(String tag, String name, String value) throws IOException 2706934ac109bf80019d70ea684c203f12ca58c365emike ritter { 2716934ac109bf80019d70ea684c203f12ca58c365emike ritter tag(tag, name, value, false); 2726934ac109bf80019d70ea684c203f12ca58c365emike ritter } 2736934ac109bf80019d70ea684c203f12ca58c365emike ritter 2746934ac109bf80019d70ea684c203f12ca58c365emike ritter /** 2756934ac109bf80019d70ea684c203f12ca58c365emike ritter * Internal method for writing a tag with attributes. 2766934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param tag the tag name 2776934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param names the names of the attributes 2786934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param values the values of the attributes 2796934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param nattr the number of attributes 2806934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param close true to close the tag, false to leave it 2816934ac109bf80019d70ea684c203f12ca58c365emike ritter * open and adjust the spacing 2826934ac109bf80019d70ea684c203f12ca58c365emike ritter */ 2836934ac109bf80019d70ea684c203f12ca58c365emike ritter protected void tag(String tag, ArrayList names, ArrayList values, 2846934ac109bf80019d70ea684c203f12ca58c365emike ritter int nattr, boolean close) throws IOException 2856934ac109bf80019d70ea684c203f12ca58c365emike ritter { 2866934ac109bf80019d70ea684c203f12ca58c365emike ritter spacing(); 2876934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write('<'); 2886934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write(tag); 2896934ac109bf80019d70ea684c203f12ca58c365emike ritter for ( int i=0; i<nattr; ++i ) { 2906934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write(' '); 2916934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write((String)names.get(i)); 2926934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write('='); 2936934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write('\"'); 2946934ac109bf80019d70ea684c203f12ca58c365emike ritter escapeString((String)values.get(i)); 2956934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write('\"'); 2966934ac109bf80019d70ea684c203f12ca58c365emike ritter } 2976934ac109bf80019d70ea684c203f12ca58c365emike ritter if ( close ) m_out.write('/'); 2986934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write('>'); 2996934ac109bf80019d70ea684c203f12ca58c365emike ritter writeln(); 3006934ac109bf80019d70ea684c203f12ca58c365emike ritter 3016934ac109bf80019d70ea684c203f12ca58c365emike ritter if ( !close ) { 3026934ac109bf80019d70ea684c203f12ca58c365emike ritter m_tagStack.add(tag); 3036934ac109bf80019d70ea684c203f12ca58c365emike ritter } 3046934ac109bf80019d70ea684c203f12ca58c365emike ritter } 3056934ac109bf80019d70ea684c203f12ca58c365emike ritter 3066934ac109bf80019d70ea684c203f12ca58c365emike ritter /** 3076934ac109bf80019d70ea684c203f12ca58c365emike ritter * Write a closed tag with attributes. The tag will be followed by a 3086934ac109bf80019d70ea684c203f12ca58c365emike ritter * newline. 3096934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param tag the tag name 3106934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param names the names of the attributes 3116934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param values the values of the attributes 3126934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param nattr the number of attributes 3136934ac109bf80019d70ea684c203f12ca58c365emike ritter */ 3146934ac109bf80019d70ea684c203f12ca58c365emike ritter public void tag(String tag, ArrayList names, ArrayList values, int nattr) throws IOException 3156934ac109bf80019d70ea684c203f12ca58c365emike ritter { 3166934ac109bf80019d70ea684c203f12ca58c365emike ritter tag(tag, names, values, nattr, true); 3176934ac109bf80019d70ea684c203f12ca58c365emike ritter } 3186934ac109bf80019d70ea684c203f12ca58c365emike ritter 3196934ac109bf80019d70ea684c203f12ca58c365emike ritter /** 3206934ac109bf80019d70ea684c203f12ca58c365emike ritter * Write a start tag with attributes. The tag will be followed by a 3216934ac109bf80019d70ea684c203f12ca58c365emike ritter * newline, and the indentation level will be increased. 3226934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param tag the tag name 3236934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param names the names of the attributes 3246934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param values the values of the attributes 3256934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param nattr the number of attributes 3266934ac109bf80019d70ea684c203f12ca58c365emike ritter */ 3276934ac109bf80019d70ea684c203f12ca58c365emike ritter public void start(String tag, ArrayList names, ArrayList values, int nattr) throws IOException 3286934ac109bf80019d70ea684c203f12ca58c365emike ritter { 3296934ac109bf80019d70ea684c203f12ca58c365emike ritter tag(tag, names, values, nattr, false); 3306934ac109bf80019d70ea684c203f12ca58c365emike ritter } 3316934ac109bf80019d70ea684c203f12ca58c365emike ritter 3326934ac109bf80019d70ea684c203f12ca58c365emike ritter /** 3336934ac109bf80019d70ea684c203f12ca58c365emike ritter * Write a start tag without attributes. The tag will be followed by a 3346934ac109bf80019d70ea684c203f12ca58c365emike ritter * newline, and the indentation level will be increased. 3356934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param tag the tag name 3366934ac109bf80019d70ea684c203f12ca58c365emike ritter */ 3376934ac109bf80019d70ea684c203f12ca58c365emike ritter public void start(String tag) throws IOException { 3386934ac109bf80019d70ea684c203f12ca58c365emike ritter tag(tag, (String[])null, null, 0, false); 3396934ac109bf80019d70ea684c203f12ca58c365emike ritter } 3406934ac109bf80019d70ea684c203f12ca58c365emike ritter 3416934ac109bf80019d70ea684c203f12ca58c365emike ritter /** 3426934ac109bf80019d70ea684c203f12ca58c365emike ritter * Close the most recently opened tag. The tag will be followed by a 3436934ac109bf80019d70ea684c203f12ca58c365emike ritter * newline, and the indentation level will be decreased. 3446934ac109bf80019d70ea684c203f12ca58c365emike ritter */ 3456934ac109bf80019d70ea684c203f12ca58c365emike ritter public void end() throws IOException { 3466934ac109bf80019d70ea684c203f12ca58c365emike ritter String tag = (String)m_tagStack.remove(m_tagStack.size()-1); 3476934ac109bf80019d70ea684c203f12ca58c365emike ritter spacing(); 3486934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write('<'); 3496934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write('/'); 3506934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write(tag); 3516934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write('>'); 3526934ac109bf80019d70ea684c203f12ca58c365emike ritter writeln(); 3536934ac109bf80019d70ea684c203f12ca58c365emike ritter } 3546934ac109bf80019d70ea684c203f12ca58c365emike ritter 3556934ac109bf80019d70ea684c203f12ca58c365emike ritter /** 3566934ac109bf80019d70ea684c203f12ca58c365emike ritter * Write a new content tag with a single attribute, consisting of an 3576934ac109bf80019d70ea684c203f12ca58c365emike ritter * open tag, content text, and a closing tag, all on one line. 3586934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param tag the tag name 3596934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param name the name of the attribute 3606934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param value the value of the attribute, this text will be escaped 3616934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param content the text content, this text will be escaped 3626934ac109bf80019d70ea684c203f12ca58c365emike ritter */ 3636934ac109bf80019d70ea684c203f12ca58c365emike ritter public void contentTag(String tag, String name, String value, String content) throws IOException 3646934ac109bf80019d70ea684c203f12ca58c365emike ritter { 3656934ac109bf80019d70ea684c203f12ca58c365emike ritter spacing(); 3666934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write('<'); m_out.write(tag); m_out.write(' '); 3676934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write(name); m_out.write('='); 3686934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write('\"'); escapeString(value); m_out.write('\"'); 3696934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write('>'); 3706934ac109bf80019d70ea684c203f12ca58c365emike ritter escapeString(content); 3716934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write('<'); m_out.write('/'); m_out.write(tag); m_out.write('>'); 3726934ac109bf80019d70ea684c203f12ca58c365emike ritter writeln(); 3736934ac109bf80019d70ea684c203f12ca58c365emike ritter } 3746934ac109bf80019d70ea684c203f12ca58c365emike ritter 3756934ac109bf80019d70ea684c203f12ca58c365emike ritter /** 3766934ac109bf80019d70ea684c203f12ca58c365emike ritter * Write a new content tag with no attributes, consisting of an 3776934ac109bf80019d70ea684c203f12ca58c365emike ritter * open tag, content text, and a closing tag, all on one line. 3786934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param tag the tag name 3796934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param content the text content, this text will be escaped 3806934ac109bf80019d70ea684c203f12ca58c365emike ritter */ 3816934ac109bf80019d70ea684c203f12ca58c365emike ritter public void contentTag(String tag, String content) throws IOException { 3826934ac109bf80019d70ea684c203f12ca58c365emike ritter spacing(); 3836934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write('<'); m_out.write(tag); m_out.write('>'); 3846934ac109bf80019d70ea684c203f12ca58c365emike ritter escapeString(content); 3856934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write('<'); m_out.write('/'); m_out.write(tag); m_out.write('>'); 3866934ac109bf80019d70ea684c203f12ca58c365emike ritter writeln(); 3876934ac109bf80019d70ea684c203f12ca58c365emike ritter } 3886934ac109bf80019d70ea684c203f12ca58c365emike ritter 3896934ac109bf80019d70ea684c203f12ca58c365emike ritter /** 3906934ac109bf80019d70ea684c203f12ca58c365emike ritter * Write content text. 3916934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param content the content text, this text will be escaped 3926934ac109bf80019d70ea684c203f12ca58c365emike ritter */ 3936934ac109bf80019d70ea684c203f12ca58c365emike ritter public void content(String content) throws IOException { 3946934ac109bf80019d70ea684c203f12ca58c365emike ritter escapeString(content); 3956934ac109bf80019d70ea684c203f12ca58c365emike ritter } 3966934ac109bf80019d70ea684c203f12ca58c365emike ritter 3976934ac109bf80019d70ea684c203f12ca58c365emike ritter /** 3986934ac109bf80019d70ea684c203f12ca58c365emike ritter * Finish the XML document. 3996934ac109bf80019d70ea684c203f12ca58c365emike ritter */ 4006934ac109bf80019d70ea684c203f12ca58c365emike ritter public void finish() throws IOException { 4016934ac109bf80019d70ea684c203f12ca58c365emike ritter m_bias = 0; 4026934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.flush(); 4036934ac109bf80019d70ea684c203f12ca58c365emike ritter } 4046934ac109bf80019d70ea684c203f12ca58c365emike ritter 4056934ac109bf80019d70ea684c203f12ca58c365emike ritter /** 4066934ac109bf80019d70ea684c203f12ca58c365emike ritter * Finish the XML document, writing the given footer text at the 4076934ac109bf80019d70ea684c203f12ca58c365emike ritter * end of the document. 4086934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param footer the footer text, this will not be escaped 4096934ac109bf80019d70ea684c203f12ca58c365emike ritter */ 4106934ac109bf80019d70ea684c203f12ca58c365emike ritter public void finish(String footer) throws IOException { 4116934ac109bf80019d70ea684c203f12ca58c365emike ritter m_bias = 0; 4126934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write(footer); 4136934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.flush(); 4146934ac109bf80019d70ea684c203f12ca58c365emike ritter } 4156934ac109bf80019d70ea684c203f12ca58c365emike ritter 4166934ac109bf80019d70ea684c203f12ca58c365emike ritter /** 4176934ac109bf80019d70ea684c203f12ca58c365emike ritter * Write the current spacing (determined by the indentation level) 4186934ac109bf80019d70ea684c203f12ca58c365emike ritter * into the document. This method is used by many of the other 4196934ac109bf80019d70ea684c203f12ca58c365emike ritter * formatting methods, and so should only need to be called in 4206934ac109bf80019d70ea684c203f12ca58c365emike ritter * the case of custom text writing outside the mechanisms 4216934ac109bf80019d70ea684c203f12ca58c365emike ritter * provided by this class. 4226934ac109bf80019d70ea684c203f12ca58c365emike ritter */ 4236934ac109bf80019d70ea684c203f12ca58c365emike ritter public void spacing() throws IOException { 4246934ac109bf80019d70ea684c203f12ca58c365emike ritter int len = m_bias + m_tagStack.size() * m_tab; 4256934ac109bf80019d70ea684c203f12ca58c365emike ritter for ( int i=0; i<len; ++i ) 4266934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write(' '); 4276934ac109bf80019d70ea684c203f12ca58c365emike ritter } 4286934ac109bf80019d70ea684c203f12ca58c365emike ritter 4296934ac109bf80019d70ea684c203f12ca58c365emike ritter // ------------------------------------------------------------------------ 4306934ac109bf80019d70ea684c203f12ca58c365emike ritter // Escape Text 4316934ac109bf80019d70ea684c203f12ca58c365emike ritter 4326934ac109bf80019d70ea684c203f12ca58c365emike ritter // unicode ranges and valid/invalid characters 4336934ac109bf80019d70ea684c203f12ca58c365emike ritter private static final char LOWER_RANGE = 0x20; 4346934ac109bf80019d70ea684c203f12ca58c365emike ritter private static final char UPPER_RANGE = 0x7f; 4356934ac109bf80019d70ea684c203f12ca58c365emike ritter private static final char[] VALID_CHARS = { 0x9, 0xA, 0xD }; 4366934ac109bf80019d70ea684c203f12ca58c365emike ritter 4376934ac109bf80019d70ea684c203f12ca58c365emike ritter private static final char[] INVALID = { '<', '>', '"', '\'', '&' }; 4386934ac109bf80019d70ea684c203f12ca58c365emike ritter private static final String[] VALID = 4396934ac109bf80019d70ea684c203f12ca58c365emike ritter { "<", ">", """, "'", "&" }; 4406934ac109bf80019d70ea684c203f12ca58c365emike ritter 4416934ac109bf80019d70ea684c203f12ca58c365emike ritter /** 4426934ac109bf80019d70ea684c203f12ca58c365emike ritter * Escape a string such that it is safe to use in an XML document. 4436934ac109bf80019d70ea684c203f12ca58c365emike ritter * @param str the string to escape 4446934ac109bf80019d70ea684c203f12ca58c365emike ritter */ 4456934ac109bf80019d70ea684c203f12ca58c365emike ritter protected void escapeString(String str) throws IOException { 4466934ac109bf80019d70ea684c203f12ca58c365emike ritter if ( str == null ) { 4476934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write("null"); 4486934ac109bf80019d70ea684c203f12ca58c365emike ritter return; 4496934ac109bf80019d70ea684c203f12ca58c365emike ritter } 4506934ac109bf80019d70ea684c203f12ca58c365emike ritter 4516934ac109bf80019d70ea684c203f12ca58c365emike ritter int len = str.length(); 4526934ac109bf80019d70ea684c203f12ca58c365emike ritter for (int i = 0; i < len; ++i) { 4536934ac109bf80019d70ea684c203f12ca58c365emike ritter char c = str.charAt(i); 4546934ac109bf80019d70ea684c203f12ca58c365emike ritter 4556934ac109bf80019d70ea684c203f12ca58c365emike ritter if ( (c < LOWER_RANGE && c != VALID_CHARS[0] && 4566934ac109bf80019d70ea684c203f12ca58c365emike ritter c != VALID_CHARS[1] && c != VALID_CHARS[2]) 4576934ac109bf80019d70ea684c203f12ca58c365emike ritter || (c > UPPER_RANGE) ) 4586934ac109bf80019d70ea684c203f12ca58c365emike ritter { 4596934ac109bf80019d70ea684c203f12ca58c365emike ritter // character out of range, escape with character value 4606934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write("&#"); 4616934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write(Integer.toString(c)); 4626934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write(';'); 4636934ac109bf80019d70ea684c203f12ca58c365emike ritter } else { 4646934ac109bf80019d70ea684c203f12ca58c365emike ritter boolean valid = true; 4656934ac109bf80019d70ea684c203f12ca58c365emike ritter // check for invalid characters (e.g., "<", "&", etc) 4666934ac109bf80019d70ea684c203f12ca58c365emike ritter for (int j=INVALID.length-1; j >= 0; --j ) 4676934ac109bf80019d70ea684c203f12ca58c365emike ritter { 4686934ac109bf80019d70ea684c203f12ca58c365emike ritter if ( INVALID[j] == c) { 4696934ac109bf80019d70ea684c203f12ca58c365emike ritter valid = false; 4706934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write(VALID[j]); 4716934ac109bf80019d70ea684c203f12ca58c365emike ritter break; 4726934ac109bf80019d70ea684c203f12ca58c365emike ritter } 4736934ac109bf80019d70ea684c203f12ca58c365emike ritter } 4746934ac109bf80019d70ea684c203f12ca58c365emike ritter // if character is valid, don't escape 4756934ac109bf80019d70ea684c203f12ca58c365emike ritter if (valid) { 4766934ac109bf80019d70ea684c203f12ca58c365emike ritter m_out.write(c); 4776934ac109bf80019d70ea684c203f12ca58c365emike ritter } 4786934ac109bf80019d70ea684c203f12ca58c365emike ritter } 4796934ac109bf80019d70ea684c203f12ca58c365emike ritter } 4806934ac109bf80019d70ea684c203f12ca58c365emike ritter } 4816934ac109bf80019d70ea684c203f12ca58c365emike ritter 4826934ac109bf80019d70ea684c203f12ca58c365emike ritter} // end of class XMLWriter 4836934ac109bf80019d70ea684c203f12ca58c365emike ritter 484