XMLStreamWriter.java

Go to the documentation of this file.
00001 
00002 //
00003 // XML storage classes version 1.3
00004 //
00005 // XMLStreamWriter.java
00006 //
00007 // Copyright (c) 2004, 2005, 2006, 2007 Martin Fuchs <martin-fuchs@gmx.net>
00008 //
00009 
00010 
00011 /*
00012 
00013  All rights reserved.
00014 
00015  Redistribution and use in source and binary forms, with or without
00016  modification, are permitted provided that the following conditions are met:
00017 
00018  * Redistributions of source code must retain the above copyright
00019     notice, this list of conditions and the following disclaimer.
00020  * Redistributions in binary form must reproduce the above copyright
00021     notice, this list of conditions and the following disclaimer in
00022     the documentation and/or other materials provided with the
00023     distribution.
00024 
00025  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00026  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00028  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00029  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00030  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00031  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00032  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00033  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00034  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00035  POSSIBILITY OF SUCH DAMAGE.
00036 
00037 */
00038 
00039 package de.mfuchs.xmlstorage.stream;
00040 
00041 import java.io.BufferedWriter;
00042 import java.io.FileWriter;
00043 import java.io.IOException;
00044 import java.io.Writer;
00045 import java.util.Map;
00046 import java.util.Stack;
00047 
00048 import de.mfuchs.xmlstorage.XMLHeader;
00049 import de.mfuchs.xmlstorage.XMLHelper;
00050 import de.mfuchs.xmlstorage.XMLNode;
00051 
00052 
00053 /**
00054  * XMLStreamWriter is used to write XML streams in XMLStorage.
00055  */
00056 public class XMLStreamWriter
00057 {
00058      // PRETTY_FLAGS
00059     public static final int PRETTY_PLAIN    = 0;
00060     public static final int PRETTY_LINEFEED = 1;
00061     public static final int PRETTY_INDENT   = 2;
00062 
00063 
00064     public XMLStreamWriter(Writer out) throws IOException
00065     {
00066         this(out, PRETTY_INDENT, new XMLHeader());
00067     }
00068 
00069     public XMLStreamWriter(final String path) throws IOException
00070     {
00071         this(path, PRETTY_INDENT, new XMLHeader());
00072     }
00073 
00074     public XMLStreamWriter(Writer out, int/*PRETTY_FLAGS*/ pretty, final XMLHeader header) throws IOException
00075     {
00076         _out = out;
00077         _pretty = pretty;
00078 
00079         header.print(_out, false);
00080     }
00081 
00082     public XMLStreamWriter(final String path, int/*PRETTY_FLAGS*/ pretty, final XMLHeader header) throws IOException
00083     {
00084          _out = new BufferedWriter(new FileWriter(path));
00085          _pretty = pretty;
00086 
00087         header.print(_out, false);
00088     }
00089 
00090     public void close() throws IOException
00091     {
00092         _out.write('\n');
00093         _out.close();
00094     }
00095 
00096      /// create node and move to it
00097     public void create(final String name) throws IOException
00098     {
00099         if (!_stack.empty()) {
00100             StackEntry last = (StackEntry) _stack.peek();
00101 
00102             if (last._state < PRE_CLOSED) {
00103                 writeAttributes(last);
00104                 closePre(last);
00105             }
00106 
00107             last._children = true;
00108         }
00109 
00110         StackEntry entry = new StackEntry(name);
00111         _stack.push(entry);
00112 
00113         writePre(entry);
00114     }
00115 
00116      /// go back to previous position
00117     public boolean back() throws IOException
00118     {
00119         if (!_stack.empty()) {
00120             writePost((StackEntry)_stack.peek());
00121 
00122             _stack.pop();
00123 
00124             return true;
00125         } else
00126             return false;
00127     }
00128 
00129      /// attribute setting
00130     public void put(String attrName, Object value)
00131     {
00132         if (!_stack.empty()) {
00133             XMLNode.AttributeMap attributes = ((StackEntry)_stack.peek())._attributes;
00134 
00135             if (value != null)
00136                 attributes.put(attrName, value.toString());
00137             else
00138                 attributes.remove(attrName);
00139         }
00140     }
00141 
00142      /// attribute setting
00143     public void put(String attrName, String value)
00144     {
00145         if (!_stack.empty()) {
00146             XMLNode.AttributeMap attributes = ((StackEntry)_stack.peek())._attributes;
00147 
00148             if (value != null)
00149                 attributes.put(attrName, value);
00150             else
00151                 attributes.remove(attrName);
00152         }
00153     }
00154 
00155     public void setContent(final String s)
00156     {
00157         setContent(s, false);
00158     }
00159 
00160     public void setContent(final String s, boolean cdata)
00161     {
00162         if (!_stack.empty())
00163             ((StackEntry)_stack.peek())._content = s!=null? XMLHelper.encodeXMLString(s, cdata): "";
00164     }
00165 
00166     // protected enum WRITESTATE
00167     protected static final int NOTHING     = 0;
00168     /*protected static final int PRE       = 1*/
00169     protected static final int ATTRIBUTES  = 2;
00170     protected static final int PRE_CLOSED  = 3;
00171     /*protected static final int CONTENT   = 4;*/
00172     protected static final int POST        = 5;
00173 
00174     protected Writer    _out;
00175     protected int/*PRETTY_FLAGS*/    _pretty;
00176 
00177     /**
00178      * StackEntry is used to hold state information when moving between nodes.
00179      */
00180     protected static class StackEntry {
00181         final String            _nodeName;
00182         XMLNode.AttributeMap    _attributes = new XMLNode.AttributeMap();
00183         String                  _content = "";
00184         int/*WRITESTATE*/       _state;
00185         boolean                 _children;
00186 
00187         StackEntry(String nodeName)
00188         {
00189             _nodeName = nodeName;
00190             _children = false;
00191             _state = NOTHING;
00192         }
00193     };
00194 
00195     protected Stack<StackEntry> _stack = new Stack<StackEntry>();
00196 
00197 //  protected static final String s_empty_attr = "";
00198 
00199     protected void closePre(StackEntry entry) throws IOException
00200     {
00201         _out.write('>');
00202 
00203         entry._state = PRE_CLOSED;
00204     }
00205 
00206     protected void writePre(StackEntry entry) throws IOException
00207     {
00208         if (_pretty >= PRETTY_LINEFEED)
00209             _out.write('\n');
00210 
00211         if (_pretty == PRETTY_INDENT)
00212             for(int i=_stack.size(); --i>0; )
00213                 _out.write(XMLNode.XML_INDENT_SPACE);
00214 
00215         _out.write("<" + XMLHelper.encodeXMLString(entry._nodeName));
00216         //entry._state = PRE;
00217     }
00218 
00219     protected void writeAttributes(StackEntry entry) throws IOException
00220     {
00221         for(Map.Entry<String,String> it: entry._attributes.entrySet())
00222             _out.write(" " + XMLHelper.encodeXMLString(it.getKey()) +
00223                        "=\"" + XMLHelper.encodeXMLString(it.getValue()) + "\"");
00224 
00225         entry._state = ATTRIBUTES;
00226     }
00227 
00228     protected void writePost(StackEntry entry) throws IOException
00229     {
00230         if (entry._state < ATTRIBUTES)
00231             writeAttributes(entry);
00232 
00233         if (entry._children || entry._content.length()>0) {
00234             if (entry._state < PRE_CLOSED)
00235                 closePre(entry);
00236 
00237             _out.write(entry._content);
00238             //entry._state = CONTENT;
00239 
00240             if (_pretty>=PRETTY_LINEFEED && entry._content.length()==0)
00241                 _out.write('\n');
00242 
00243             if (_pretty==PRETTY_INDENT && entry._content.length()==0)
00244                 for(int i=_stack.size(); --i>0; )
00245                     _out.write(XMLNode.XML_INDENT_SPACE);
00246 
00247             _out.write("</" + XMLHelper.encodeXMLString(entry._nodeName) + ">");
00248         } else {
00249             _out.write("/>");
00250         }
00251 
00252         entry._state = POST;
00253     }
00254 }