Clover coverage report - dom4j - 1.6.1
Coverage timestamp: ma mei 16 2005 14:23:01 GMT+01:00
file stats: LOC: 1.934   Methods: 93
NCLOC: 1.101   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
XMLWriter.java 59,5% 64,3% 57% 62,3%
coverage coverage
 1    /*
 2    * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
 3    *
 4    * This software is open source.
 5    * See the bottom of this file for the licence.
 6    */
 7   
 8    package org.dom4j.io;
 9   
 10    import java.io.BufferedWriter;
 11    import java.io.IOException;
 12    import java.io.OutputStream;
 13    import java.io.OutputStreamWriter;
 14    import java.io.UnsupportedEncodingException;
 15    import java.io.Writer;
 16    import java.util.HashMap;
 17    import java.util.Iterator;
 18    import java.util.List;
 19    import java.util.Map;
 20    import java.util.StringTokenizer;
 21   
 22    import org.dom4j.Attribute;
 23    import org.dom4j.CDATA;
 24    import org.dom4j.Comment;
 25    import org.dom4j.Document;
 26    import org.dom4j.DocumentType;
 27    import org.dom4j.Element;
 28    import org.dom4j.Entity;
 29    import org.dom4j.Namespace;
 30    import org.dom4j.Node;
 31    import org.dom4j.ProcessingInstruction;
 32    import org.dom4j.Text;
 33    import org.dom4j.tree.NamespaceStack;
 34   
 35    import org.xml.sax.Attributes;
 36    import org.xml.sax.InputSource;
 37    import org.xml.sax.Locator;
 38    import org.xml.sax.SAXException;
 39    import org.xml.sax.SAXNotRecognizedException;
 40    import org.xml.sax.SAXNotSupportedException;
 41    import org.xml.sax.XMLReader;
 42    import org.xml.sax.ext.LexicalHandler;
 43    import org.xml.sax.helpers.XMLFilterImpl;
 44   
 45    /**
 46    * <p>
 47    * <code>XMLWriter</code> takes a DOM4J tree and formats it to a stream as
 48    * XML. It can also take SAX events too so can be used by SAX clients as this
 49    * object implements the {@link org.xml.sax.ContentHandler}and {@link
 50    * LexicalHandler} interfaces. as well. This formatter performs typical document
 51    * formatting. The XML declaration and processing instructions are always on
 52    * their own lines. An {@link OutputFormat}object can be used to define how
 53    * whitespace is handled when printing and allows various configuration options,
 54    * such as to allow suppression of the XML declaration, the encoding declaration
 55    * or whether empty documents are collapsed.
 56    * </p>
 57    *
 58    * <p>
 59    * There are <code>write(...)</code> methods to print any of the standard
 60    * DOM4J classes, including <code>Document</code> and <code>Element</code>,
 61    * to either a <code>Writer</code> or an <code>OutputStream</code>.
 62    * Warning: using your own <code>Writer</code> may cause the writer's
 63    * preferred character encoding to be ignored. If you use encodings other than
 64    * UTF8, we recommend using the method that takes an OutputStream instead.
 65    * </p>
 66    *
 67    * @author <a href="mailto:jstrachan@apache.org">James Strachan </a>
 68    * @author Joseph Bowbeer
 69    * @version $Revision: 1.83.2.2 $
 70    */
 71    public class XMLWriter extends XMLFilterImpl implements LexicalHandler {
 72    private static final String PAD_TEXT = " ";
 73   
 74    protected static final String[] LEXICAL_HANDLER_NAMES = {
 75    "http://xml.org/sax/properties/lexical-handler",
 76    "http://xml.org/sax/handlers/LexicalHandler"};
 77   
 78    protected static final OutputFormat DEFAULT_FORMAT = new OutputFormat();
 79   
 80    /** Should entityRefs by resolved when writing ? */
 81    private boolean resolveEntityRefs = true;
 82   
 83    /**
 84    * Stores the last type of node written so algorithms can refer to the
 85    * previous node type
 86    */
 87    protected int lastOutputNodeType;
 88   
 89    /**
 90    * Stores if the last written element node was a closing tag or an opening
 91    * tag.
 92    */
 93    private boolean lastElementClosed = false;
 94   
 95    /** Stores the xml:space attribute value of preserve for whitespace flag */
 96    protected boolean preserve = false;
 97   
 98    /** The Writer used to output to */
 99    protected Writer writer;
 100   
 101    /** The Stack of namespaceStack written so far */
 102    private NamespaceStack namespaceStack = new NamespaceStack();
 103   
 104    /** The format used by this writer */
 105    private OutputFormat format;
 106   
 107    /** whether we should escape text */
 108    private boolean escapeText = true;
 109   
 110    /**
 111    * The initial number of indentations (so you can print a whole document
 112    * indented, if you like)
 113    */
 114    private int indentLevel = 0;
 115   
 116    /** buffer used when escaping strings */
 117    private StringBuffer buffer = new StringBuffer();
 118   
 119    /**
 120    * whether we have added characters before from the same chunk of characters
 121    */
 122    private boolean charsAdded = false;
 123   
 124    private char lastChar;
 125   
 126    /** Whether a flush should occur after writing a document */
 127    private boolean autoFlush;
 128   
 129    /** Lexical handler we should delegate to */
 130    private LexicalHandler lexicalHandler;
 131   
 132    /**
 133    * Whether comments should appear inside DTD declarations - defaults to
 134    * false
 135    */
 136    private boolean showCommentsInDTDs;
 137   
 138    /** Is the writer curerntly inside a DTD definition? */
 139    private boolean inDTD;
 140   
 141    /** The namespaces used for the current element when consuming SAX events */
 142    private Map namespacesMap;
 143   
 144    /**
 145    * what is the maximum allowed character code such as 127 in US-ASCII (7
 146    * bit) or 255 in ISO- (8 bit) or -1 to not escape any characters (other
 147    * than the special XML characters like &lt; &gt; &amp;)
 148    */
 149    private int maximumAllowedCharacter;
 150   
 151  18 public XMLWriter(Writer writer) {
 152  18 this(writer, DEFAULT_FORMAT);
 153    }
 154   
 155  2143 public XMLWriter(Writer writer, OutputFormat format) {
 156  2143 this.writer = writer;
 157  2143 this.format = format;
 158  2143 namespaceStack.push(Namespace.NO_NAMESPACE);
 159    }
 160   
 161  2 public XMLWriter() {
 162  2 this.format = DEFAULT_FORMAT;
 163  2 this.writer = new BufferedWriter(new OutputStreamWriter(System.out));
 164  2 this.autoFlush = true;
 165  2 namespaceStack.push(Namespace.NO_NAMESPACE);
 166    }
 167   
 168  2 public XMLWriter(OutputStream out) throws UnsupportedEncodingException {
 169  2 this.format = DEFAULT_FORMAT;
 170  2 this.writer = createWriter(out, format.getEncoding());
 171  2 this.autoFlush = true;
 172  2 namespaceStack.push(Namespace.NO_NAMESPACE);
 173    }
 174   
 175  7 public XMLWriter(OutputStream out, OutputFormat format)
 176    throws UnsupportedEncodingException {
 177  7 this.format = format;
 178  7 this.writer = createWriter(out, format.getEncoding());
 179  7 this.autoFlush = true;
 180  7 namespaceStack.push(Namespace.NO_NAMESPACE);
 181    }
 182   
 183  8 public XMLWriter(OutputFormat format) throws UnsupportedEncodingException {
 184  8 this.format = format;
 185  8 this.writer = createWriter(System.out, format.getEncoding());
 186  8 this.autoFlush = true;
 187  8 namespaceStack.push(Namespace.NO_NAMESPACE);
 188    }
 189   
 190  2 public void setWriter(Writer writer) {
 191  2 this.writer = writer;
 192  2 this.autoFlush = false;
 193    }
 194   
 195  8 public void setOutputStream(OutputStream out)
 196    throws UnsupportedEncodingException {
 197  8 this.writer = createWriter(out, format.getEncoding());
 198  8 this.autoFlush = true;
 199    }
 200   
 201    /**
 202    * DOCUMENT ME!
 203    *
 204    * @return true if text thats output should be escaped. This is enabled by
 205    * default. It could be disabled if the output format is textual,
 206    * like in XSLT where we can have xml, html or text output.
 207    */
 208  0 public boolean isEscapeText() {
 209  0 return escapeText;
 210    }
 211   
 212    /**
 213    * Sets whether text output should be escaped or not. This is enabled by
 214    * default. It could be disabled if the output format is textual, like in
 215    * XSLT where we can have xml, html or text output.
 216    *
 217    * @param escapeText
 218    * DOCUMENT ME!
 219    */
 220  1 public void setEscapeText(boolean escapeText) {
 221  1 this.escapeText = escapeText;
 222    }
 223   
 224    /**
 225    * Set the initial indentation level. This can be used to output a document
 226    * (or, more likely, an element) starting at a given indent level, so it's
 227    * not always flush against the left margin. Default: 0
 228    *
 229    * @param indentLevel
 230    * the number of indents to start with
 231    */
 232  0 public void setIndentLevel(int indentLevel) {
 233  0 this.indentLevel = indentLevel;
 234    }
 235   
 236    /**
 237    * Returns the maximum allowed character code that should be allowed
 238    * unescaped which defaults to 127 in US-ASCII (7 bit) or 255 in ISO- (8
 239    * bit).
 240    *
 241    * @return DOCUMENT ME!
 242    */
 243  484095 public int getMaximumAllowedCharacter() {
 244  484095 if (maximumAllowedCharacter == 0) {
 245  2147 maximumAllowedCharacter = defaultMaximumAllowedCharacter();
 246    }
 247   
 248  484095 return maximumAllowedCharacter;
 249    }
 250   
 251    /**
 252    * Sets the maximum allowed character code that should be allowed unescaped
 253    * such as 127 in US-ASCII (7 bit) or 255 in ISO- (8 bit) or -1 to not
 254    * escape any characters (other than the special XML characters like &lt;
 255    * &gt; &amp;) If this is not explicitly set then it is defaulted from the
 256    * encoding.
 257    *
 258    * @param maximumAllowedCharacter
 259    * The maximumAllowedCharacter to set
 260    */
 261  1 public void setMaximumAllowedCharacter(int maximumAllowedCharacter) {
 262  1 this.maximumAllowedCharacter = maximumAllowedCharacter;
 263    }
 264   
 265    /**
 266    * Flushes the underlying Writer
 267    *
 268    * @throws IOException
 269    * DOCUMENT ME!
 270    */
 271  2119 public void flush() throws IOException {
 272  2119 writer.flush();
 273    }
 274   
 275    /**
 276    * Closes the underlying Writer
 277    *
 278    * @throws IOException
 279    * DOCUMENT ME!
 280    */
 281  21 public void close() throws IOException {
 282  21 writer.close();
 283    }
 284   
 285    /**
 286    * Writes the new line text to the underlying Writer
 287    *
 288    * @throws IOException
 289    * DOCUMENT ME!
 290    */
 291  113 public void println() throws IOException {
 292  113 writer.write(format.getLineSeparator());
 293    }
 294   
 295    /**
 296    * Writes the given {@link Attribute}.
 297    *
 298    * @param attribute
 299    * <code>Attribute</code> to output.
 300    *
 301    * @throws IOException
 302    * DOCUMENT ME!
 303    */
 304  0 public void write(Attribute attribute) throws IOException {
 305  0 writeAttribute(attribute);
 306   
 307  0 if (autoFlush) {
 308  0 flush();
 309    }
 310    }
 311   
 312    /**
 313    * <p>
 314    * This will print the <code>Document</code> to the current Writer.
 315    * </p>
 316    *
 317    * <p>
 318    * Warning: using your own Writer may cause the writer's preferred character
 319    * encoding to be ignored. If you use encodings other than UTF8, we
 320    * recommend using the method that takes an OutputStream instead.
 321    * </p>
 322    *
 323    * <p>
 324    * Note: as with all Writers, you may need to flush() yours after this
 325    * method returns.
 326    * </p>
 327    *
 328    * @param doc
 329    * <code>Document</code> to format.
 330    *
 331    * @throws IOException
 332    * if there's any problem writing.
 333    */
 334  113 public void write(Document doc) throws IOException {
 335  113 writeDeclaration();
 336   
 337  113 if (doc.getDocType() != null) {
 338  1 indent();
 339  1 writeDocType(doc.getDocType());
 340    }
 341   
 342  113 for (int i = 0, size = doc.nodeCount(); i < size; i++) {
 343  116 Node node = doc.node(i);
 344  116 writeNode(node);
 345    }
 346   
 347  113 writePrintln();
 348   
 349  113 if (autoFlush) {
 350  16 flush();
 351    }
 352    }
 353   
 354    /**
 355    * <p>
 356    * Writes the <code>{@link Element}</code>, including its <code>{@link
 357    * Attribute}</code>
 358    * s, and its value, and all its content (child nodes) to the current
 359    * Writer.
 360    * </p>
 361    *
 362    * @param element
 363    * <code>Element</code> to output.
 364    *
 365    * @throws IOException
 366    * DOCUMENT ME!
 367    */
 368  2043 public void write(Element element) throws IOException {
 369  2043 writeElement(element);
 370   
 371  2043 if (autoFlush) {
 372  2 flush();
 373    }
 374    }
 375   
 376    /**
 377    * Writes the given {@link CDATA}.
 378    *
 379    * @param cdata
 380    * <code>CDATA</code> to output.
 381    *
 382    * @throws IOException
 383    * DOCUMENT ME!
 384    */
 385  0 public void write(CDATA cdata) throws IOException {
 386  0 writeCDATA(cdata.getText());
 387   
 388  0 if (autoFlush) {
 389  0 flush();
 390    }
 391    }
 392   
 393    /**
 394    * Writes the given {@link Comment}.
 395    *
 396    * @param comment
 397    * <code>Comment</code> to output.
 398    *
 399    * @throws IOException
 400    * DOCUMENT ME!
 401    */
 402  0 public void write(Comment comment) throws IOException {
 403  0 writeComment(comment.getText());
 404   
 405  0 if (autoFlush) {
 406  0 flush();
 407    }
 408    }
 409   
 410    /**
 411    * Writes the given {@link DocumentType}.
 412    *
 413    * @param docType
 414    * <code>DocumentType</code> to output.
 415    *
 416    * @throws IOException
 417    * DOCUMENT ME!
 418    */
 419  0 public void write(DocumentType docType) throws IOException {
 420  0 writeDocType(docType);
 421   
 422  0 if (autoFlush) {
 423  0 flush();
 424    }
 425    }
 426   
 427    /**
 428    * Writes the given {@link Entity}.
 429    *
 430    * @param entity
 431    * <code>Entity</code> to output.
 432    *
 433    * @throws IOException
 434    * DOCUMENT ME!
 435    */
 436  0 public void write(Entity entity) throws IOException {
 437  0 writeEntity(entity);
 438   
 439  0 if (autoFlush) {
 440  0 flush();
 441    }
 442    }
 443   
 444    /**
 445    * Writes the given {@link Namespace}.
 446    *
 447    * @param namespace
 448    * <code>Namespace</code> to output.
 449    *
 450    * @throws IOException
 451    * DOCUMENT ME!
 452    */
 453  0 public void write(Namespace namespace) throws IOException {
 454  0 writeNamespace(namespace);
 455   
 456  0 if (autoFlush) {
 457  0 flush();
 458    }
 459    }
 460   
 461    /**
 462    * Writes the given {@link ProcessingInstruction}.
 463    *
 464    * @param processingInstruction
 465    * <code>ProcessingInstruction</code> to output.
 466    *
 467    * @throws IOException
 468    * DOCUMENT ME!
 469    */
 470  0 public void write(ProcessingInstruction processingInstruction)
 471    throws IOException {
 472  0 writeProcessingInstruction(processingInstruction);
 473   
 474  0 if (autoFlush) {
 475  0 flush();
 476    }
 477    }
 478   
 479    /**
 480    * <p>
 481    * Print out a {@link String}, Perfoms the necessary entity escaping and
 482    * whitespace stripping.
 483    * </p>
 484    *
 485    * @param text
 486    * is the text to output
 487    *
 488    * @throws IOException
 489    * DOCUMENT ME!
 490    */
 491  0 public void write(String text) throws IOException {
 492  0 writeString(text);
 493   
 494  0 if (autoFlush) {
 495  0 flush();
 496    }
 497    }
 498   
 499    /**
 500    * Writes the given {@link Text}.
 501    *