cdc.io.data.xml.XmlDataWriter Maven / Gradle / Ivy
package cdc.io.data.xml;
import java.io.Closeable;
import java.io.File;
import java.io.Flushable;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import cdc.io.compress.Compressor;
import cdc.io.data.Attribute;
import cdc.io.data.Child;
import cdc.io.data.Comment;
import cdc.io.data.Document;
import cdc.io.data.Element;
import cdc.io.data.Node;
import cdc.io.data.Text;
import cdc.io.data.TextKind;
import cdc.io.xml.XmlWriter;
/**
* Class used to save data Nodes as XML.
*
* @author Damien Carbonne
*
*/
public class XmlDataWriter implements Closeable, Flushable {
protected static final Logger LOGGER = LogManager.getLogger(XmlDataWriter.class);
private final XmlWriter writer;
public XmlDataWriter(XmlWriter writer) {
this.writer = writer;
}
public XmlDataWriter(Writer writer) {
this.writer = new XmlWriter(writer);
}
public XmlDataWriter(OutputStream os) throws IOException {
this(os, StandardCharsets.UTF_8.name());
}
public XmlDataWriter(OutputStream os,
String encoding)
throws IOException {
this.writer = new XmlWriter(os, encoding);
}
public XmlDataWriter(PrintStream out) throws IOException {
this(out, StandardCharsets.UTF_8.name());
}
public XmlDataWriter(PrintStream out,
String encoding)
throws IOException {
this.writer = new XmlWriter(out, encoding);
}
public XmlDataWriter(String filename,
String encoding,
Compressor compressor)
throws IOException {
this.writer = new XmlWriter(filename, encoding, compressor);
}
public XmlDataWriter(String filename,
String encoding)
throws IOException {
this.writer = new XmlWriter(filename, encoding, Compressor.NONE);
}
public XmlDataWriter(String filename,
Compressor compressor)
throws IOException {
this.writer = new XmlWriter(filename, StandardCharsets.UTF_8.name(), compressor);
}
public XmlDataWriter(String filename) throws IOException {
this(filename, StandardCharsets.UTF_8.name(), Compressor.NONE);
}
public XmlDataWriter(File file,
String encoding,
Compressor compressor)
throws IOException {
this.writer = new XmlWriter(file, encoding, compressor);
}
public XmlDataWriter(File file,
String encoding)
throws IOException {
this.writer = new XmlWriter(file, encoding, Compressor.NONE);
}
public XmlDataWriter(File file,
Compressor compressor)
throws IOException {
this.writer = new XmlWriter(file, StandardCharsets.UTF_8.name(), compressor);
}
public XmlDataWriter(File file) throws IOException {
this(file, StandardCharsets.UTF_8.name(), Compressor.NONE);
}
/**
* @return The underlying XmlWriter.
*/
public final XmlWriter getXmlWriter() {
return writer;
}
/**
* Writes a node.
*
* @param node The node.
* @throws IOException When an IO error occurs.
*/
public void write(Node node) throws IOException {
write(writer, node);
}
/**
* Writes a node to an XmlWriter.
*
* @param writer The XmlWriter.
* @param node The node.
* @param asDocument If {@code true} and {@code node} is not a document, inserts
* XML heading {@code } before writing
* the {@code node}.
* If {@code false} and {@code node} is not a document, directly writes the node.
* If {@code node} is a document, this has no effect.
* @throws IOException When an IO error occurs.
*/
public static void write(XmlWriter writer,
Node node,
boolean asDocument) throws IOException {
if (!asDocument || node instanceof Document) {
write(writer, node);
} else {
writer.beginDocument();
write(writer, node);
writer.endDocument();
}
}
/**
* Writes a node to an XmlWriter.
*
* If {@code node} is not a document, XML heading {@code }
* is not inserted.
* Use {@link #write(XmlWriter, Node, boolean)} for that.
*
* @param writer The XmlWriter.
* @param node The node.
* @throws IOException When an IO error occurs.
*/
public static void write(XmlWriter writer,
Node node) throws IOException {
switch (node.getType()) {
case COMMENT:
final Comment comment = (Comment) node;
writer.addComment(comment.getContent());
break;
case DOCUMENT:
final Document document = (Document) node;
writer.beginDocument();
if (document.hasDTD()) {
writer.addDTD("\n" + document.getDTD() + "\n");
}
for (final Child child : document.getChildren()) {
write(writer, child);
}
writer.endDocument();
break;
case ELEMENT:
final Element element = (Element) node;
writer.beginElement(element.getName());
if (element.hasAttributes()) {
for (final Attribute attribute : element.getAttributes()) {
writer.addAttribute(attribute.getName(), attribute.getValue());
}
}
if (element.hasChildren()) {
if (element.hasChildren(Text.class)) {
// Force mixed content layout
writer.addElementContent("");
}
for (final Child child : element.getChildren()) {
write(writer, child);
}
}
writer.endElement();
break;
case TEXT:
final Text text = (Text) node;
if (text.getKind() == TextKind.CDATA) {
writer.addCData(text.getContent());
} else {
writer.addElementContent(text.getContent());
}
break;
default:
// Ignore
break;
}
}
@Override
public void close() throws IOException {
writer.close();
}
@Override
public void flush() throws IOException {
writer.flush();
}
private void write(Node node,
boolean asDocument,
String indent,
XmlWriter.Feature... features) throws IOException {
writer.setEnabled(features);
if (indent != null) {
writer.setEnabled(XmlWriter.Feature.PRETTY_PRINT, true);
}
if (!asDocument) {
writer.setEnabled(XmlWriter.Feature.ALLOW_PARTIAL_XML, true);
}
writer.setIndentString(indent);
write(writer, node, asDocument);
writer.flush();
}
/**
* Prints a Node to a PrintStream.
*
* @param node The node.
* @param asDocument If {@code true} and {@code node} is not a document, inserts
* XML heading {@code } before writing
* the {@code node}.
* If {@code false} and {@code node} is not a document, directly writes the node.
* If {@code node} is a document, this has no effect.
* @param out The PrintStream.
* @param indent Indent string. If not null, pretty printing is enabled.
* @param close If {@code true}, {@code out} is closed in the end.
* @param features The XmlWriter features to enable.
* @throws IOException When an IO error occurs.
*/
public static void print(Node node,
boolean asDocument,
PrintStream out,
String indent,
boolean close,
XmlWriter.Feature... features) throws IOException {
final XmlDataWriter writer = new XmlDataWriter(out);
writer.write(node, asDocument, indent, features);
if (close) {
writer.close();
}
}
/**
* Prints a Document to a PrintStream.
*
* @param doc The document.
* @param out The PrintStream.
* @param indent Indent string. If not null, pretty printing is enabled.
* @param close If {@code true}, {@code out} is closed in the end.
* @param features The XmlWriter features to enable.
* @throws IOException When an IO error occurs.
*/
public static void print(Document doc,
PrintStream out,
String indent,
boolean close,
XmlWriter.Feature... features) throws IOException {
print(doc, false, out, indent, close, features);
}
/**
* Saves a Node to a Writer.
*
* @param node The node.
* @param asDocument If {@code true} and {@code node} is not a document, inserts
* XML heading {@code } before writing
* the {@code node}.
* If {@code false} and {@code node} is not a document, directly writes the node.
* If {@code node} is a document, this has no effect.
* @param writer The writer.
* @param indent Indent string. If not null, pretty printing is enabled.
* @param features The XmlWriter features to enable.
* @throws IOException When an IO error occurs.
*/
public static void save(Node node,
boolean asDocument,
Writer writer,
String indent,
XmlWriter.Feature... features) throws IOException {
try (final XmlDataWriter w = new XmlDataWriter(writer)) {
w.write(node, asDocument, indent, features);
}
}
/**
* Saves a Document to a Writer.
*
* @param doc The document.
* @param writer The writer.
* @param indent Indent string. If not null, pretty printing is enabled.
* @param features The XmlWriter features to enable.
* @throws IOException When an IO error occurs.
*/
public static void save(Document doc,
Writer writer,
String indent,
XmlWriter.Feature... features) throws IOException {
save(doc, false, writer, indent, features);
}
/**
* Saves a Node to an OutputStream.
*
* @param node The node.
* @param asDocument If {@code true} and {@code node} is not a document, inserts
* XML heading {@code } before writing
* the {@code node}.
* If {@code false} and {@code node} is not a document, directly writes the node.
* If {@code node} is a document, this has no effect.
* @param os The output stream.
* @param indent Indent string. If not null, pretty printing is enabled.
* @param features The XmlWriter features to enable.
* @throws IOException When an IO error occurs.
*/
public static void save(Node node,
boolean asDocument,
OutputStream os,
String indent,
XmlWriter.Feature... features) throws IOException {
try (final XmlDataWriter writer = new XmlDataWriter(os)) {
writer.write(node, asDocument, indent, features);
}
}
/**
* Saves a Document to an OutputStream.
*
* @param doc The document.
* @param os The output stream.
* @param indent Indent string. If not null, pretty printing is enabled.
* @param features The XmlWriter features to enable.
* @throws IOException When an IO error occurs.
*/
public static void save(Document doc,
OutputStream os,
String indent,
XmlWriter.Feature... features) throws IOException {
save(doc, false, os, indent, features);
}
/**
* Saves a Node to a File.
*
* @param node The node.
* @param asDocument If {@code true} and {@code node} is not a document, inserts
* XML heading {@code } before writing
* the {@code node}.
* If {@code false} and {@code node} is not a document, directly writes the node.
* If {@code node} is a document, this has no effect.
* @param filename The file name.
* @param indent Indent string. If not null, pretty printing is enabled.
* @param features The XmlWriter features to enable.
* @throws IOException When an IO error occurs.
*/
public static void save(Node node,
boolean asDocument,
String filename,
String indent,
XmlWriter.Feature... features) throws IOException {
try (final XmlDataWriter writer = new XmlDataWriter(filename)) {
writer.write(node, asDocument, indent, features);
}
}
/**
* Saves a Document to a File.
*
* @param doc The document.
* @param filename The file name.
* @param indent Indent string. If not null, pretty printing is enabled.
* @param features The XmlWriter features to enable.
* @throws IOException When an IO error occurs.
*/
public static void save(Document doc,
String filename,
String indent,
XmlWriter.Feature... features) throws IOException {
save(doc, false, filename, indent, features);
}
/**
* Saves a Node to a File.
*
* @param node The node.
* @param asDocument If {@code true} and {@code node} is not a document, inserts
* XML heading {@code } before writing
* the {@code node}.
* If {@code false} and {@code node} is not a document, directly writes the node.
* If {@code node} is a document, this has no effect.
* @param file The file.
* @param indent Indent string. If not null, pretty printing is enabled.
* @param features The XmlWriter features to enable.
* @throws IOException When an IO error occurs.
*/
public static void save(Node node,
boolean asDocument,
File file,
String indent,
XmlWriter.Feature... features) throws IOException {
save(node, asDocument, file.getPath(), indent, features);
}
/**
* Saves a Document to a File.
*
* @param doc The document.
* @param file The file.
* @param indent Indent string. If not null, pretty printing is enabled.
* @param features The XmlWriter features to enable.
* @throws IOException When an IO error occurs.
*/
public static void save(Document doc,
File file,
String indent,
XmlWriter.Feature... features) throws IOException {
save(doc, false, file, indent, features);
}
public static String toString(Document doc,
String indent,
XmlWriter.Feature... features) {
try (StringWriter writer = new StringWriter()) {
save(doc, writer, indent, features);
return writer.toString();
} catch (final IOException e) {
LOGGER.catching(e);
}
return null;
}
public static String toString(Node node,
boolean asDocument,
String indent,
XmlWriter.Feature... features) {
try (StringWriter writer = new StringWriter()) {
save(node, asDocument, writer, indent, features);
return writer.toString();
} catch (final IOException e) {
LOGGER.catching(e);
}
return null;
}
}