blob: ed8aa97eb59a18921ff64433e75809c7b3adaa6e [file] [log] [blame]
package org.eclipse.net4j.util.io;
import org.eclipse.net4j.util.HexUtil;
import org.eclipse.net4j.util.WrappedException;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.util.LinkedList;
/**
* @author Eike Stepper
* @since 3.1
*/
public class XMLOutput
{
private static final AttributesImpl NO_ATTRIBUTES = new AttributesImpl();
private TransformerHandler xmlHandler;
private char[] newLine;
private char[] indentation;
private LinkedList<Element> stack = new LinkedList<Element>();
private Element element;
public XMLOutput(OutputStream out) throws TransformerConfigurationException, SAXException
{
setNewLine("\n");
setIndentation(" ");
SAXTransformerFactory factory = (SAXTransformerFactory)SAXTransformerFactory.newInstance();
xmlHandler = factory.newTransformerHandler();
Transformer transformer = xmlHandler.getTransformer();
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.VERSION, "1.0");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
xmlHandler.setResult(new StreamResult(out));
xmlHandler.startDocument();
}
public void setNewLine(String newLine)
{
this.newLine = newLine.toCharArray();
}
public void setIndentation(String indentation)
{
this.indentation = indentation.toCharArray();
}
public XMLOutput element(String name) throws SAXException
{
flush();
element = new Element(name);
return this;
}
public XMLOutput attribute(String name, Object value) throws SAXException
{
if (value != null)
{
return attributeOrNull(name, value);
}
return this;
}
public XMLOutput attributeOrNull(String name, Object value) throws SAXException
{
checkElement();
element.addAttribute(name, value);
return this;
}
public Writer characters() throws SAXException
{
checkElement();
newLine();
element.start();
xmlHandler.startCDATA();
return new Writer()
{
@Override
public void write(char[] cbuf, int off, int len) throws IOException
{
try
{
xmlHandler.characters(cbuf, off, len);
}
catch (SAXException ex)
{
throw WrappedException.wrap(ex);
}
}
@Override
public void flush() throws IOException
{
// Do nothing
}
@Override
public void close() throws IOException
{
try
{
xmlHandler.endCDATA();
element.end();
}
catch (SAXException ex)
{
throw WrappedException.wrap(ex);
}
finally
{
element = null;
}
}
};
}
public OutputStream bytes() throws SAXException
{
checkElement();
newLine();
element.start();
xmlHandler.startCDATA();
return new OutputStream()
{
@Override
public void write(byte[] b, int off, int len) throws IOException
{
try
{
char[] cbuf = HexUtil.bytesToHex(b, off, len).toCharArray();
xmlHandler.characters(cbuf, 0, cbuf.length);
}
catch (SAXException ex)
{
throw WrappedException.wrap(ex);
}
}
@Override
public void write(int i) throws IOException
{
byte b = (byte)((i & 0xff) + Byte.MIN_VALUE);
byte[] bs = { b };
write(bs, 0, 1);
}
@Override
public void close() throws IOException
{
try
{
xmlHandler.endCDATA();
element.end();
}
catch (SAXException ex)
{
throw WrappedException.wrap(ex);
}
finally
{
element = null;
}
}
};
}
public XMLOutput push() throws SAXException
{
newLine();
element.start();
stack.add(element);
element = null;
return this;
}
public XMLOutput pop() throws SAXException
{
flush();
Element element = stack.removeLast();
if (element.hasChildren())
{
newLine();
}
element.end();
return this;
}
public void done() throws SAXException
{
while (!stack.isEmpty())
{
pop();
}
xmlHandler.endDocument();
}
private void flush() throws SAXException
{
if (element != null)
{
newLine();
element.start();
element.end();
element = null;
}
}
private void newLine() throws SAXException
{
xmlHandler.ignorableWhitespace(newLine, 0, newLine.length);
for (int i = 0; i < stack.size(); i++)
{
xmlHandler.ignorableWhitespace(indentation, 0, indentation.length);
}
}
private void checkElement()
{
if (element == null)
{
throw new IllegalStateException("No element");
}
}
/**
* @author Eike Stepper
*/
private final class Element
{
private String name;
private AttributesImpl attributes;
private boolean children;
public Element(String name)
{
this.name = name;
}
public boolean hasChildren()
{
return children;
}
public void addChild()
{
children = true;
}
public void addAttribute(String name, Object value)
{
if (attributes == null)
{
attributes = new AttributesImpl();
}
if (value == null)
{
value = "";
}
attributes.addAttribute("", "", name, "", value.toString());
}
public void start() throws SAXException
{
if (!stack.isEmpty())
{
stack.getLast().addChild();
}
xmlHandler.startElement("", "", name, attributes == null ? NO_ATTRIBUTES : attributes);
}
public void end() throws SAXException
{
xmlHandler.endElement("", "", name);
}
}
}