Package com.topologi.diffx.xml

Source Code of com.topologi.diffx.xml.XMLWriterBase

/*
* 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.
*
* <p>Provides methods to generate well-formed XML data easily. wrapping a writer.
*
* <p>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".
*
* <p>The recommended implementation is to use a <code>BufferedWriter</code> to write.
*
* <pre>
*  Writer writer =
*     new BufferedWriter(new OutputStreamWriter(new FileOutputStream("foo.out"),"utf-8"));
* </pre>
*
* @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.
   *
   * <p>This attribute changes depending on the state of the instance.
   */
  int depth = 0;

  /**
   * Indicates whether the xml should be indented or not.
   *
   * <p>The default is <code>true</code> (indented).
   *
   * <p>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 -------------------------------------------------------------------------

  /**
   * <p>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 <code>null</code>.
   */
  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("<?xml version=\"1.0\" encoding=\""+this.encoding+"\"?>");
    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.
   *
   * <p>The encoding must match the encoding used if there is an underlying
   * <code>OutputStreamWriter</code>.
   *
   * @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.
   *
   * <p>Does nothing if the object is <code>null</code>.
   *
   * @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("<!-- ");
    this.writer.write(comment);
    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("<![CDATA[");
    this.writer.write(data);
    this.writer.write(end);
  }

  // Attribute methods
  // ----------------------------------------------------------------------------------------------

  /**
   * {@inheritDoc}
   */
  @Override
  public final void attribute(String name, String value)
      throws IOException {
    if (!this.isNude) throw new IllegalStateException("Cannot write attribute: too late!");
    this.writer.write(' ');
    this.writer.write(name);
    this.writer.write('=');
    this.writer.write('"');
    this.writerEscape.writeAttValue(value);
    this.writer.write('"');
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public final void attribute(String name, int value)
      throws IOException {
    if (!this.isNude) throw new IllegalStateException("Cannot write attribute: too late!");
    this.writer.write(' ');
    this.writer.write(name);
    this.writer.write('=');
    this.writer.write('"');
    this.writer.write(Integer.toString(value));
    this.writer.write('"');
  }

  // Open/close specific elements
  // ----------------------------------------------------------------------------------------------

  /**
   * {@inheritDoc}
   */
  @Override
  public void element(String name, String text) throws IOException {
    this.openElement(name);
    this.writeText(text);
    closeElement();
  }

  // Direct access to the writer
  // ----------------------------------------------------------------------------------------------

  /**
   * {@inheritDoc}
   */
  @Override
  public final void flush() throws IOException {
    this.writer.flush();
  }

  // Base class and convenience methods
  // ----------------------------------------------------------------------------------------------

  /**
   * Writes the end of the open element tag.
   *
   * <p>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 <code>indent</code> flag is set to <code>true</code>.
   *
   * @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.
   *
   * <p>This method exists so that we can explicitly say that we should do nothing
   * in certain conditions.
   */
  static final void doNothing() {
    return;
  }

}
TOP

Related Classes of com.topologi.diffx.xml.XMLWriterBase

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.