aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/zwobble/mammoth/internal/xml/XmlWriter.java
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2016-11-13 22:10:33 +0000
committerMichael Williamson <mike@zwobble.org>2016-11-13 22:10:33 +0000
commit559c31d2f28d9a77655538d994c3213d916b8d0c (patch)
tree4710ad7e21c102220ba212c12b3f754945b5a370 /src/main/java/org/zwobble/mammoth/internal/xml/XmlWriter.java
parent34cb98fb564d82e185103c85ead8443a7d551c6b (diff)
Ensure embedded style map is not removed by Word
Diffstat (limited to 'src/main/java/org/zwobble/mammoth/internal/xml/XmlWriter.java')
-rw-r--r--src/main/java/org/zwobble/mammoth/internal/xml/XmlWriter.java139
1 files changed, 139 insertions, 0 deletions
diff --git a/src/main/java/org/zwobble/mammoth/internal/xml/XmlWriter.java b/src/main/java/org/zwobble/mammoth/internal/xml/XmlWriter.java
new file mode 100644
index 0000000..7882258
--- /dev/null
+++ b/src/main/java/org/zwobble/mammoth/internal/xml/XmlWriter.java
@@ -0,0 +1,139 @@
+package org.zwobble.mammoth.internal.xml;
+
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import java.io.ByteArrayOutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+public class XmlWriter {
+ public static String toString(XmlElement element, NamespacePrefixes namespaces) {
+ try {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ XmlWriter writer = new XmlWriter(createXmlWriter(outputStream), namespaces);
+ writer.writeDocument(element);
+ return new String(outputStream.toByteArray(), StandardCharsets.UTF_8);
+ } catch (XMLStreamException exception) {
+ throw new RuntimeException(exception);
+ }
+ }
+
+ private static XMLStreamWriter createXmlWriter(ByteArrayOutputStream outputStream) throws XMLStreamException {
+ XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
+ return outputFactory.createXMLStreamWriter(outputStream);
+ }
+
+ private final XMLStreamWriter writer;
+ private final NamespacePrefixes namespaces;
+
+ private XmlWriter(XMLStreamWriter writer, NamespacePrefixes namespaces) {
+ this.writer = writer;
+ this.namespaces = namespaces;
+ }
+
+ private void writeDocument(XmlElement element) throws XMLStreamException {
+ writer.writeStartDocument("UTF-8", "1.0");
+ writeStartElement(element);
+ writeNamespaces(namespaces);
+ writeAttributes(element);
+ writeNodes(element.getChildren());
+ writer.writeEndElement();
+ writer.writeEndDocument();
+ }
+
+ private void writeNodes(List<XmlNode> children) {
+ for (XmlNode child : children) {
+ writeNode(child);
+ }
+ }
+
+ private void writeNode(XmlNode child) {
+ child.accept(new XmlNodeVisitor<Object>() {
+ @Override
+ public Object visit(XmlElement element) {
+ try {
+ writeStartElement(element);
+ writeAttributes(element);
+ writeNodes(element.getChildren());
+ writer.writeEndElement();
+ } catch (XMLStreamException exception) {
+ throw new RuntimeException(exception);
+ }
+ return null;
+ }
+
+ @Override
+ public Object visit(XmlTextNode textNode) {
+ try {
+ writer.writeCharacters(textNode.getValue());
+ } catch (XMLStreamException exception) {
+ throw new RuntimeException(exception);
+ }
+ return null;
+ }
+ });
+ }
+
+ private void writeNamespaces(NamespacePrefixes namespaces) throws XMLStreamException {
+ for (NamespacePrefix namespace : namespaces) {
+ Optional<String> prefix = namespace.getPrefix();
+ if (prefix.isPresent()) {
+ writer.writeNamespace(prefix.get(), namespace.getUri());
+ } else {
+ writer.writeDefaultNamespace(namespace.getUri());
+ }
+ }
+ }
+
+ private void writeStartElement(XmlElement element) throws XMLStreamException {
+ XmlName name = readName(element.getName());
+ Optional<String> prefix = name.namespace.getPrefix();
+ if (prefix.isPresent()) {
+ writer.writeStartElement(prefix.get(), name.localName, name.namespace.getUri());
+ } else {
+ writer.writeStartElement(name.localName);
+ }
+ }
+
+ private void writeAttributes(XmlElement element) throws XMLStreamException {
+ for (Map.Entry<String, String> attribute : element.getAttributes().entrySet()) {
+ writeAttribute(attribute);
+ }
+ }
+
+ private void writeAttribute(Map.Entry<String, String> attribute) throws XMLStreamException {
+ XmlName name = readName(attribute.getKey());
+ Optional<String> prefix = name.namespace.getPrefix();
+ if (prefix.isPresent()) {
+ writer.writeAttribute(prefix.get(), name.namespace.getUri(), name.localName, attribute.getValue());
+ } else {
+ writer.writeAttribute(name.localName, attribute.getValue());
+ }
+ }
+
+ private XmlName readName(String name) {
+ String[] parts = name.split(":", 2);
+ if (parts.length == 1) {
+ return new XmlName(namespaces.defaultNamespace().get(), parts[0]);
+ } else {
+ String prefix = parts[0];
+ String localName = parts[1];
+ NamespacePrefix namespace = namespaces.lookupPrefix(prefix)
+ .orElseThrow(() -> new RuntimeException("Could not find namespace for prefix: " + prefix));
+ return new XmlName(namespace, localName);
+ }
+ }
+
+ private static class XmlName {
+ private final NamespacePrefix namespace;
+ private final String localName;
+
+ private XmlName(NamespacePrefix namespace, String localName) {
+ this.namespace = namespace;
+ this.localName = localName;
+ }
+ }
+}