com.topologi.diffx.xml.XMLWriterBase Maven / Gradle / Ivy
Show all versions of docx4j Show documentation
/*
* This file is part of the DiffX library.
*
* For licensing information please see the file license.txt included in the release.
* A copy of this licence can also be found at
* http://www.opensource.org/licenses/artistic-license-2.0.php
*/
package com.topologi.diffx.xml;
import java.io.IOException;
import java.io.Writer;
import com.topologi.diffx.xml.esc.XMLEscapeWriter;
import com.topologi.diffx.xml.esc.XMLEscapeWriterUTF8;
/**
* A base implementation for XML writers.
*
* Provides methods to generate well-formed XML data easily. wrapping a writer.
*
*
This version only supports utf-8 encoding, if writing to a file make sure that the
* encoding of the file output stream is "utf-8".
*
*
The recommended implementation is to use a BufferedWriter
to write.
*
*
* Writer writer =
* new BufferedWriter(new OutputStreamWriter(new FileOutputStream("foo.out"),"utf-8"));
*
*
* @author Christophe Lauret
* @version 17 May 2005
*/
abstract class XMLWriterBase implements XMLWriter {
/**
* Where the XML data goes.
*/
final Writer writer;
/**
* Encoding of the output xml.
*/
String encoding = "utf-8";
/**
* Encoding of the output xml.
*/
XMLEscapeWriter writerEscape;
/**
* Level of the depth of the xml document currently produced.
*
* This attribute changes depending on the state of the instance.
*/
int depth = 0;
/**
* Indicates whether the xml should be indented or not.
*
*
The default is true
(indented).
*
*
The indentation is 2 white-spaces.
*/
boolean indent;
/**
* The default indentation spaces used.
*/
private String indentChars = null;
/**
* Flag to indicate that the element open tag is not finished yet.
*/
boolean isNude = false;
// constructors -------------------------------------------------------------------------
/**
*
Creates a new XML writer.
*
* @param writer Where this writer should write the XML data.
* @param indent Set the indentation flag.
*
* @throws NullPointerException If the writer is null
.
*/
public XMLWriterBase(Writer writer, boolean indent) throws NullPointerException {
if (writer == null)
throw new NullPointerException("XMLWriter cannot use a null writer.");
this.writer = writer;
this.writerEscape = new XMLEscapeWriterUTF8(writer);
this.indent = indent;
if (indent) {
this.indentChars = " ";
}
}
// setup methods ------------------------------------------------------------------------
/**
* {@inheritDoc}
*/
@Override
public final void xmlDecl() throws IOException {
this.writer.write("");
if (this.indent) {
this.writer.write('\n');
}
}
/**
* {@inheritDoc}
*/
@Override
public final void setIndentChars(String spaces) throws IllegalStateException, IllegalArgumentException {
if (this.depth != 0)
throw new IllegalStateException("To late to set the indentation characters!");
// check that this is a valid indentation string
if (spaces != null) {
for (int i = 0; i < spaces.length(); i++) {
if (!Character.isSpaceChar(spaces.charAt(i)))
throw new IllegalArgumentException("Not a valid indentation string.");
}
}
// update the flags
this.indentChars = spaces;
this.indent = spaces != null;
}
/**
* Sets the encoding to use.
*
*
The encoding must match the encoding used if there is an underlying
* OutputStreamWriter
.
*
* @param encoding The encoding to use.
*
* @throws IllegalArgumentException If the encoding is not valid.
* @throws IllegalStateException If the writer has already been used.
*/
public final void setEncoding(String encoding) throws IllegalStateException, IllegalArgumentException {
if (this.depth != 0)
throw new IllegalStateException("To late to set the encoding!");
this.encoding = encoding;
}
// Write text methods
// ----------------------------------------------------------------------------------------------
/**
* {@inheritDoc}
*/
@Override
public final void writeText(String text) throws IOException {
if (text == null) return;
deNude();
this.writerEscape.writeText(text);
}
/**
* {@inheritDoc}
*/
@Override
public final void writeText(char[] text, int off, int len) throws IOException {
deNude();
this.writerEscape.writeText(text, off, len);
}
/**
* {@inheritDoc}
*/
@Override
public final void writeText(char c) throws IOException {
deNude();
this.writerEscape.writeText(c);
}
/**
* Writes the string value of an object.
*
*
Does nothing if the object is null
.
*
* @see Object#toString
* @see #writeText(java.lang.String)
*
* @param o The object that should be written as text.
*
* @throws IOException If thrown by the wrapped writer.
*/
public final void writeText(Object o) throws IOException {
// TODO: what about an XML serializable ???
// TODO: Add to interface ???
if (o != null) {
this.writeText(o.toString());
}
}
// Write XML methods
// ----------------------------------------------------------------------------------------------
/**
* {@inheritDoc}
*/
@Override
public final void writeXML(String text) throws IOException {
if (text == null) return;
deNude();
this.writer.write(text);
}
/**
* {@inheritDoc}
*/
@Override
public final void writeXML(char[] text, int off, int len) throws IOException {
deNude();
this.writer.write(text, off, len);
}
// Processing Instructions, CDATA sections and comments
// ----------------------------------------------------------------------------------------------
/**
* {@inheritDoc}
*/
@Override
public final void writeComment(String comment) throws IOException, IllegalArgumentException {
if (comment == null)
return;
if (comment.indexOf("--") >= 0)
throw new IllegalArgumentException("A comment must not contain '--'.");
deNude();
this.writer.write("");
if (this.indent) {
this.writer.write('\n');
}
}
/**
* {@inheritDoc}
*/
@Override
public final void writePI(String target, String data) throws IOException {
deNude();
this.writer.write("");
this.writer.write(target);
this.writer.write(' ');
this.writer.write(data);
this.writer.write("?>");
if (this.indent) {
this.writer.write('\n');
}
}
/**
* {@inheritDoc}
*/
@Override
public final void writeCDATA(String data) throws IOException {
if (data == null) return;
final String end = "]]>";
if (data.indexOf(end) >= 0)
throw new IllegalArgumentException("CDATA sections must not contain \']]>\'");
deNude();
this.writer.write("After this method is invoked it is not possible to write attributes
* for an element.
*
* @throws IOException If thrown by the wrapped writer.
*/
abstract void deNude() throws IOException;
/**
* Insert the correct amount of space characterss depending on the depth and if
* the indent
flag is set to true
.
*
* @throws IOException If thrown by the wrapped writer.
*/
void indent() throws IOException {
if (this.indent) {
for (int i = 0; i < this.depth; i++) {
this.writer.write(this.indentChars);
}
}
}
/**
* Does nothing.
*
*
This method exists so that we can explicitly say that we should do nothing
* in certain conditions.
*/
static final void doNothing() {
return;
}
}