package com.ausregistry.jtoolkit2.xml;
import java.io.ByteArrayOutputStream;
import java.util.logging.Logger;
import javax.xml.namespace.NamespaceContext;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import com.ausregistry.jtoolkit2.ErrorPkg;
/**
* A prefixless XML document builder implementation. That is, a default
* namespace is always in effect on each element. This is generally optimal
* for EPP, since there are very few nodes in the tree at which the namespace
* changes. This is only published outside the scope of the package to support
* representation of {@link org.w3c.dom.Node}s as an XML String.
*
*
* Uses the debug, maintenance and user level loggers.
*/
public final class XMLBuilderSJSXP implements XMLBuilder {
private static final int BUFFER_SIZE = 4096;
private static XMLOutputFactory xmlOutputFactory;
/// XML encoding.
private static String enc;
/// XML version.
private static String vers;
private ByteArrayOutputStream bufferStream;
private XMLStreamWriter writer;
private String pname;
private NamespaceContext namespaceContext;
private final Package classPackage;
static {
xmlOutputFactory = XMLOutputFactory.newInstance();
enc = "UTF-8";
vers = "1.0";
}
public XMLBuilderSJSXP() {
this(vers, enc, false);
}
XMLBuilderSJSXP(String version, String encoding, boolean standalone) {
vers = version;
enc = encoding;
try {
writer = xmlOutputFactory.createXMLStreamWriter(bufferStream,
encoding);
} catch (XMLStreamException xse) {
Logger.getLogger(pname + ".maint").severe(xse.getMessage());
Logger.getLogger(pname + ".user").severe(
ErrorPkg.getMessage("xml.writer.config.fail.msg"));
}
}
static void setVersion(String version) {
vers = version;
}
static void setEncoding(String encoding) {
enc = encoding;
}
{
classPackage = getClass().getPackage();
pname = classPackage.getName();
namespaceContext = new NamespaceContextImpl();
bufferStream = new ByteArrayOutputStream(BUFFER_SIZE);
}
@Override
public String toXML(Element root) {
return toXML(root, enc, vers);
}
public String toXML(Element root, String encoding, String version) {
try {
writer.writeStartDocument(encoding, version);
String toolkitVersion = getToolkitVersion();
if (!toolkitVersion.isEmpty()) {
writer.writeComment(toolkitVersion);
}
dfs(root);
writer.flush();
} catch (XMLStreamException xse) {
Logger.getLogger(pname + ".maint").severe(xse.getMessage());
xse.printStackTrace();
Logger.getLogger(pname + ".user").severe(
ErrorPkg.getMessage("xml.writer.process.fail.msg"));
}
return bufferStream.toString();
}
public String partialToXML(Node topNode) {
try {
writer.setNamespaceContext(namespaceContext);
dfs((Element) topNode, (Element) topNode);
writer.flush();
} catch (XMLStreamException xse) {
Logger.getLogger(pname + ".maint").severe(xse.getMessage());
xse.printStackTrace();
Logger.getLogger(pname + ".user").severe(
ErrorPkg.getMessage("xml.writer.process.fail.msg"));
}
return bufferStream.toString();
}
private void dfs(Element e) throws XMLStreamException {
writer.setNamespaceContext(namespaceContext);
dfs(e, null);
}
private void dfs(Element e, Element parent) throws XMLStreamException {
String uri = e.getNamespaceURI();
String prefix = e.lookupPrefix(uri);
String localName = e.getLocalName();
if (localName == null) {
localName = e.getNodeName();
}
Logger.getLogger(pname + ".debug").finer("Writing element " + localName);
if (prefix == null) {
writer.setDefaultNamespace(uri);
} else {
writer.setPrefix(prefix, uri);
}
if (e.hasChildNodes()) {
writer.writeStartElement(uri, localName);
} else {
writer.writeEmptyElement(uri, localName);
}
if (parent == null
|| (uri != null && !parent.getNamespaceURI().equals(uri))) {
Logger.getLogger(pname + ".debug").finer(
"Writing default namespace for element " + e.getLocalName());
if (prefix == null) {
writer.writeDefaultNamespace(uri);
}
}
if (e.hasAttributes()) {
NamedNodeMap attributes = e.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
Node attr = attributes.item(i);
String name = attr.getNodeName();
String value = attr.getNodeValue();
if (!(name.startsWith("xmlns") && value.equals(uri))) {
writer.writeAttribute(name, value);
}
}
}
if (e.hasChildNodes()) {
NodeList children = e.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node child = children.item(i);
if (child instanceof Text) {
writer.writeCharacters(child.getNodeValue());
}
if (child instanceof Element) {
dfs((Element) child, e);
}
}
}
if (e.hasChildNodes()) {
writer.writeEndElement();
}
}
private String getToolkitVersion() {
String specificationTitle = classPackage.getSpecificationTitle();
if (specificationTitle != null) {
return specificationTitle + " v" + classPackage.getSpecificationVersion();
} else {
return "";
}
}
}