mirror of https://github.com/apache/maven.git
[MNG-6036] Add namespace to XmlNode (#1318)
This commit is contained in:
parent
eee037e676
commit
05fcf5b2d3
|
@ -30,8 +30,6 @@ import org.apache.maven.api.annotations.ThreadSafe;
|
||||||
/**
|
/**
|
||||||
* An immutable xml node.
|
* An immutable xml node.
|
||||||
*
|
*
|
||||||
* TODO: v4: add support for namespaces
|
|
||||||
*
|
|
||||||
* @since 4.0.0
|
* @since 4.0.0
|
||||||
*/
|
*/
|
||||||
@Experimental
|
@Experimental
|
||||||
|
@ -82,6 +80,12 @@ public interface XmlNode {
|
||||||
@Nonnull
|
@Nonnull
|
||||||
String getName();
|
String getName();
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
String getNamespaceUri();
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
String getPrefix();
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
String getValue();
|
String getValue();
|
||||||
|
|
||||||
|
@ -106,8 +110,6 @@ public interface XmlNode {
|
||||||
|
|
||||||
XmlNode merge(@Nullable XmlNode source, @Nullable Boolean childMergeOverride);
|
XmlNode merge(@Nullable XmlNode source, @Nullable Boolean childMergeOverride);
|
||||||
|
|
||||||
XmlNode clone();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merge recessive into dominant and return either {@code dominant}
|
* Merge recessive into dominant and return either {@code dominant}
|
||||||
* with merged information or a clone of {@code recessive} if
|
* with merged information or a clone of {@code recessive} if
|
||||||
|
|
|
@ -27,9 +27,13 @@ import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.maven.api.model.Model;
|
import org.apache.maven.api.model.Model;
|
||||||
|
import org.apache.maven.api.model.Plugin;
|
||||||
|
import org.apache.maven.api.xml.XmlNode;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
|
||||||
class ModelXmlTest {
|
class ModelXmlTest {
|
||||||
|
|
||||||
|
@ -50,6 +54,38 @@ class ModelXmlTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testNamespaceInXmlNode() throws XMLStreamException {
|
||||||
|
String xml = "<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
|
||||||
|
+ " xmlns=\"http://maven.apache.org/POM/4.0.0\"\n"
|
||||||
|
+ " xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/POM/4.0.0\">\n"
|
||||||
|
+ " <build>\n"
|
||||||
|
+ " <plugins>\n"
|
||||||
|
+ " <plugin>\n"
|
||||||
|
+ " <m:configuration xmlns:m=\"http://maven.apache.org/POM/4.0.0\" xmlns=\"http://fabric8.io/fabric8-maven-plugin\">\n"
|
||||||
|
+ " <myConfig>foo</myConfig>\n"
|
||||||
|
+ " </m:configuration>\n"
|
||||||
|
+ " </plugin>\n"
|
||||||
|
+ " </plugins>\n"
|
||||||
|
+ " </build>\n"
|
||||||
|
+ "</project>";
|
||||||
|
|
||||||
|
Model model = fromXml(xml);
|
||||||
|
Plugin plugin = model.getBuild().getPlugins().get(0);
|
||||||
|
XmlNode node = plugin.getConfiguration();
|
||||||
|
assertNotNull(node);
|
||||||
|
assertEquals("http://maven.apache.org/POM/4.0.0", node.getNamespaceUri());
|
||||||
|
assertEquals("m", node.getPrefix());
|
||||||
|
assertEquals("configuration", node.getName());
|
||||||
|
assertEquals(1, node.getChildren().size());
|
||||||
|
XmlNode myConfig = node.getChildren().get(0);
|
||||||
|
assertEquals("http://fabric8.io/fabric8-maven-plugin", myConfig.getNamespaceUri());
|
||||||
|
assertEquals("", myConfig.getPrefix());
|
||||||
|
assertEquals("myConfig", myConfig.getName());
|
||||||
|
String config = node.toString();
|
||||||
|
assertFalse(config.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
String toXml(Model model) throws IOException, XMLStreamException {
|
String toXml(Model model) throws IOException, XMLStreamException {
|
||||||
StringWriter sw = new StringWriter();
|
StringWriter sw = new StringWriter();
|
||||||
MavenStaxWriter writer = new MavenStaxWriter();
|
MavenStaxWriter writer = new MavenStaxWriter();
|
||||||
|
|
|
@ -176,8 +176,10 @@ public class XmlNodeBuilder {
|
||||||
public static XmlNodeImpl build(XMLStreamReader parser, boolean trim, InputLocationBuilderStax locationBuilder)
|
public static XmlNodeImpl build(XMLStreamReader parser, boolean trim, InputLocationBuilderStax locationBuilder)
|
||||||
throws XMLStreamException {
|
throws XMLStreamException {
|
||||||
boolean spacePreserve = false;
|
boolean spacePreserve = false;
|
||||||
String name = null;
|
String lPrefix = null;
|
||||||
String value = null;
|
String lNamespaceUri = null;
|
||||||
|
String lName = null;
|
||||||
|
String lValue = null;
|
||||||
Object location = null;
|
Object location = null;
|
||||||
Map<String, String> attrs = null;
|
Map<String, String> attrs = null;
|
||||||
List<XmlNode> children = null;
|
List<XmlNode> children = null;
|
||||||
|
@ -187,31 +189,29 @@ public class XmlNodeBuilder {
|
||||||
if (eventType == XMLStreamReader.START_ELEMENT) {
|
if (eventType == XMLStreamReader.START_ELEMENT) {
|
||||||
lastStartTag = parser.getLocation().getLineNumber() * 1000
|
lastStartTag = parser.getLocation().getLineNumber() * 1000
|
||||||
+ parser.getLocation().getColumnNumber();
|
+ parser.getLocation().getColumnNumber();
|
||||||
if (name == null) {
|
if (lName == null) {
|
||||||
int namespacesSize = parser.getNamespaceCount();
|
int namespacesSize = parser.getNamespaceCount();
|
||||||
name = parser.getLocalName();
|
lPrefix = parser.getPrefix();
|
||||||
String pfx = parser.getPrefix();
|
lNamespaceUri = parser.getNamespaceURI();
|
||||||
if (pfx != null && !pfx.isEmpty()) {
|
lName = parser.getLocalName();
|
||||||
name = pfx + ":" + name;
|
|
||||||
}
|
|
||||||
location = locationBuilder != null ? locationBuilder.toInputLocation(parser) : null;
|
location = locationBuilder != null ? locationBuilder.toInputLocation(parser) : null;
|
||||||
int attributesSize = parser.getAttributeCount();
|
int attributesSize = parser.getAttributeCount();
|
||||||
if (attributesSize > 0 || namespacesSize > 0) {
|
if (attributesSize > 0 || namespacesSize > 0) {
|
||||||
attrs = new HashMap<>();
|
attrs = new HashMap<>();
|
||||||
for (int i = 0; i < namespacesSize; i++) {
|
for (int i = 0; i < namespacesSize; i++) {
|
||||||
String prefix = parser.getNamespacePrefix(i);
|
String nsPrefix = parser.getNamespacePrefix(i);
|
||||||
String namespace = parser.getNamespaceURI(i);
|
String nsUri = parser.getNamespaceURI(i);
|
||||||
attrs.put(prefix != null && !prefix.isEmpty() ? "xmlns:" + prefix : "xmlns", namespace);
|
attrs.put(nsPrefix != null && !nsPrefix.isEmpty() ? "xmlns:" + nsPrefix : "xmlns", nsUri);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < attributesSize; i++) {
|
for (int i = 0; i < attributesSize; i++) {
|
||||||
String aname = parser.getAttributeLocalName(i);
|
String aName = parser.getAttributeLocalName(i);
|
||||||
String avalue = parser.getAttributeValue(i);
|
String aValue = parser.getAttributeValue(i);
|
||||||
String apfx = parser.getAttributePrefix(i);
|
String aPrefix = parser.getAttributePrefix(i);
|
||||||
if (apfx != null && !apfx.isEmpty()) {
|
if (aPrefix != null && !aPrefix.isEmpty()) {
|
||||||
aname = apfx + ":" + aname;
|
aName = aPrefix + ":" + aName;
|
||||||
}
|
}
|
||||||
attrs.put(aname, avalue);
|
attrs.put(aName, aValue);
|
||||||
spacePreserve = spacePreserve || ("xml:space".equals(aname) && "preserve".equals(avalue));
|
spacePreserve = spacePreserve || ("xml:space".equals(aName) && "preserve".equals(aValue));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -223,17 +223,19 @@ public class XmlNodeBuilder {
|
||||||
}
|
}
|
||||||
} else if (eventType == XMLStreamReader.CHARACTERS || eventType == XMLStreamReader.CDATA) {
|
} else if (eventType == XMLStreamReader.CHARACTERS || eventType == XMLStreamReader.CDATA) {
|
||||||
String text = parser.getText();
|
String text = parser.getText();
|
||||||
value = value != null ? value + text : text;
|
lValue = lValue != null ? lValue + text : text;
|
||||||
} else if (eventType == XMLStreamReader.END_ELEMENT) {
|
} else if (eventType == XMLStreamReader.END_ELEMENT) {
|
||||||
boolean emptyTag = lastStartTag
|
boolean emptyTag = lastStartTag
|
||||||
== parser.getLocation().getLineNumber() * 1000
|
== parser.getLocation().getLineNumber() * 1000
|
||||||
+ parser.getLocation().getColumnNumber();
|
+ parser.getLocation().getColumnNumber();
|
||||||
if (value != null && trim && !spacePreserve) {
|
if (lValue != null && trim && !spacePreserve) {
|
||||||
value = value.trim();
|
lValue = lValue.trim();
|
||||||
}
|
}
|
||||||
return new XmlNodeImpl(
|
return new XmlNodeImpl(
|
||||||
name,
|
lPrefix,
|
||||||
children == null ? (value != null ? value : emptyTag ? null : "") : null,
|
lNamespaceUri,
|
||||||
|
lName,
|
||||||
|
children == null ? (lValue != null ? lValue : emptyTag ? null : "") : null,
|
||||||
attrs,
|
attrs,
|
||||||
children,
|
children,
|
||||||
location);
|
location);
|
||||||
|
|
|
@ -18,7 +18,8 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.maven.internal.xml;
|
package org.apache.maven.internal.xml;
|
||||||
|
|
||||||
import java.io.IOException;
|
import javax.xml.stream.XMLStreamException;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -31,14 +32,11 @@ import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.apache.maven.api.xml.XmlNode;
|
import org.apache.maven.api.xml.XmlNode;
|
||||||
import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter;
|
|
||||||
import org.codehaus.plexus.util.xml.SerializerXMLWriter;
|
|
||||||
import org.codehaus.plexus.util.xml.XMLWriter;
|
|
||||||
import org.codehaus.plexus.util.xml.pull.XmlSerializer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NOTE: remove all the util code in here when separated, this class should be pure data.
|
* NOTE: remove all the util code in here when separated, this class should be pure data.
|
||||||
|
@ -46,6 +44,10 @@ import org.codehaus.plexus.util.xml.pull.XmlSerializer;
|
||||||
public class XmlNodeImpl implements Serializable, XmlNode {
|
public class XmlNodeImpl implements Serializable, XmlNode {
|
||||||
private static final long serialVersionUID = 2567894443061173996L;
|
private static final long serialVersionUID = 2567894443061173996L;
|
||||||
|
|
||||||
|
protected final String prefix;
|
||||||
|
|
||||||
|
protected final String namespaceUri;
|
||||||
|
|
||||||
protected final String name;
|
protected final String name;
|
||||||
|
|
||||||
protected final String value;
|
protected final String value;
|
||||||
|
@ -70,6 +72,19 @@ public class XmlNodeImpl implements Serializable, XmlNode {
|
||||||
|
|
||||||
public XmlNodeImpl(
|
public XmlNodeImpl(
|
||||||
String name, String value, Map<String, String> attributes, List<XmlNode> children, Object location) {
|
String name, String value, Map<String, String> attributes, List<XmlNode> children, Object location) {
|
||||||
|
this("", "", name, value, attributes, children, location);
|
||||||
|
}
|
||||||
|
|
||||||
|
public XmlNodeImpl(
|
||||||
|
String prefix,
|
||||||
|
String namespaceUri,
|
||||||
|
String name,
|
||||||
|
String value,
|
||||||
|
Map<String, String> attributes,
|
||||||
|
List<XmlNode> children,
|
||||||
|
Object location) {
|
||||||
|
this.prefix = prefix == null ? "" : prefix;
|
||||||
|
this.namespaceUri = namespaceUri == null ? "" : namespaceUri;
|
||||||
this.name = Objects.requireNonNull(name);
|
this.name = Objects.requireNonNull(name);
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.attributes =
|
this.attributes =
|
||||||
|
@ -84,14 +99,21 @@ public class XmlNodeImpl implements Serializable, XmlNode {
|
||||||
return merge(this, source, childMergeOverride);
|
return merge(this, source, childMergeOverride);
|
||||||
}
|
}
|
||||||
|
|
||||||
public XmlNode clone() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
// Name handling
|
// Name handling
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPrefix() {
|
||||||
|
return prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNamespaceUri() {
|
||||||
|
return namespaceUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
@ -158,16 +180,6 @@ public class XmlNodeImpl implements Serializable, XmlNode {
|
||||||
// Helpers
|
// Helpers
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
public void writeToSerializer(String namespace, XmlSerializer serializer) throws IOException {
|
|
||||||
// TODO: WARNING! Later versions of plexus-utils psit out an <?xml ?> header due to thinking this is a new
|
|
||||||
// document - not the desired behaviour!
|
|
||||||
SerializerXMLWriter xmlWriter = new SerializerXMLWriter(namespace, serializer);
|
|
||||||
XmlNodeWriter.write(xmlWriter, this);
|
|
||||||
if (xmlWriter.getExceptions().size() > 0) {
|
|
||||||
throw (IOException) xmlWriter.getExceptions().get(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merges one DOM into another, given a specific algorithm and possible override points for that algorithm.<p>
|
* Merges one DOM into another, given a specific algorithm and possible override points for that algorithm.<p>
|
||||||
* The algorithm is as follows:
|
* The algorithm is as follows:
|
||||||
|
@ -238,7 +250,7 @@ public class XmlNodeImpl implements Serializable, XmlNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recessive.getChildren().size() > 0) {
|
if (!recessive.getChildren().isEmpty()) {
|
||||||
boolean mergeChildren = true;
|
boolean mergeChildren = true;
|
||||||
if (childMergeOverride != null) {
|
if (childMergeOverride != null) {
|
||||||
mergeChildren = childMergeOverride;
|
mergeChildren = childMergeOverride;
|
||||||
|
@ -256,7 +268,7 @@ public class XmlNodeImpl implements Serializable, XmlNode {
|
||||||
List<XmlNode> dominantChildren = dominant.getChildren().stream()
|
List<XmlNode> dominantChildren = dominant.getChildren().stream()
|
||||||
.filter(n -> n.getName().equals(name))
|
.filter(n -> n.getName().equals(name))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
if (dominantChildren.size() > 0) {
|
if (!dominantChildren.isEmpty()) {
|
||||||
commonChildren.put(name, dominantChildren.iterator());
|
commonChildren.put(name, dominantChildren.iterator());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -267,7 +279,7 @@ public class XmlNodeImpl implements Serializable, XmlNode {
|
||||||
String idValue = recessiveChild.getAttribute(ID_COMBINATION_MODE_ATTRIBUTE);
|
String idValue = recessiveChild.getAttribute(ID_COMBINATION_MODE_ATTRIBUTE);
|
||||||
|
|
||||||
XmlNode childDom = null;
|
XmlNode childDom = null;
|
||||||
if (isNotEmpty(idValue)) {
|
if (!isEmpty(idValue)) {
|
||||||
for (XmlNode dominantChild : dominant.getChildren()) {
|
for (XmlNode dominantChild : dominant.getChildren()) {
|
||||||
if (idValue.equals(dominantChild.getAttribute(ID_COMBINATION_MODE_ATTRIBUTE))) {
|
if (idValue.equals(dominantChild.getAttribute(ID_COMBINATION_MODE_ATTRIBUTE))) {
|
||||||
childDom = dominantChild;
|
childDom = dominantChild;
|
||||||
|
@ -275,7 +287,7 @@ public class XmlNodeImpl implements Serializable, XmlNode {
|
||||||
mergeChildren = true;
|
mergeChildren = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (isNotEmpty(keysValue)) {
|
} else if (!isEmpty(keysValue)) {
|
||||||
String[] keys = keysValue.split(",");
|
String[] keys = keysValue.split(",");
|
||||||
Map<String, Optional<String>> recessiveKeyValues = Stream.of(keys)
|
Map<String, Optional<String>> recessiveKeyValues = Stream.of(keys)
|
||||||
.collect(Collectors.toMap(
|
.collect(Collectors.toMap(
|
||||||
|
@ -395,23 +407,47 @@ public class XmlNodeImpl implements Serializable, XmlNode {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
try {
|
||||||
|
return toStringXml();
|
||||||
|
} catch (XMLStreamException e) {
|
||||||
|
return toStringObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toStringXml() throws XMLStreamException {
|
||||||
StringWriter writer = new StringWriter();
|
StringWriter writer = new StringWriter();
|
||||||
XmlNodeWriter.write(writer, this);
|
XmlNodeWriter.write(writer, this);
|
||||||
return writer.toString();
|
return writer.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toUnescapedString() {
|
public String toStringObject() {
|
||||||
StringWriter writer = new StringWriter();
|
StringBuilder sb = new StringBuilder();
|
||||||
XMLWriter xmlWriter = new PrettyPrintXMLWriter(writer);
|
sb.append("XmlNode[");
|
||||||
XmlNodeWriter.write(xmlWriter, this, false);
|
boolean w = false;
|
||||||
return writer.toString();
|
w = addToStringField(sb, prefix, o -> !o.isEmpty(), "prefix", w);
|
||||||
|
w = addToStringField(sb, namespaceUri, o -> !o.isEmpty(), "namespaceUri", w);
|
||||||
|
w = addToStringField(sb, name, o -> !o.isEmpty(), "name", w);
|
||||||
|
w = addToStringField(sb, value, o -> !o.isEmpty(), "value", w);
|
||||||
|
w = addToStringField(sb, attributes, o -> !o.isEmpty(), "attributes", w);
|
||||||
|
w = addToStringField(sb, children, o -> !o.isEmpty(), "children", w);
|
||||||
|
w = addToStringField(sb, location, Objects::nonNull, "location", w);
|
||||||
|
sb.append("]");
|
||||||
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isNotEmpty(String str) {
|
private static <T> boolean addToStringField(StringBuilder sb, T o, Function<T, Boolean> p, String n, boolean w) {
|
||||||
return ((str != null) && (str.length() > 0));
|
if (!p.apply(o)) {
|
||||||
|
if (w) {
|
||||||
|
sb.append(", ");
|
||||||
|
} else {
|
||||||
|
w = true;
|
||||||
|
}
|
||||||
|
sb.append(n).append("='").append(o).append('\'');
|
||||||
|
}
|
||||||
|
return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isEmpty(String str) {
|
private static boolean isEmpty(String str) {
|
||||||
return ((str == null) || (str.length() == 0));
|
return str == null || str.isEmpty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,49 +18,142 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.maven.internal.xml;
|
package org.apache.maven.internal.xml;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import javax.xml.stream.XMLOutputFactory;
|
||||||
|
import javax.xml.stream.XMLStreamException;
|
||||||
|
import javax.xml.stream.XMLStreamWriter;
|
||||||
|
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.maven.api.xml.XmlNode;
|
import org.apache.maven.api.xml.XmlNode;
|
||||||
import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter;
|
import org.codehaus.stax2.util.StreamWriterDelegate;
|
||||||
import org.codehaus.plexus.util.xml.XMLWriter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class XmlNodeWriter {
|
public class XmlNodeWriter {
|
||||||
public static void write(Writer writer, XmlNode dom) {
|
public static void write(Writer writer, XmlNode dom) throws XMLStreamException {
|
||||||
write(new PrettyPrintXMLWriter(writer), dom);
|
XMLOutputFactory factory = new com.ctc.wstx.stax.WstxOutputFactory();
|
||||||
|
factory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, false);
|
||||||
|
factory.setProperty(com.ctc.wstx.api.WstxOutputProperties.P_USE_DOUBLE_QUOTES_IN_XML_DECL, true);
|
||||||
|
factory.setProperty(com.ctc.wstx.api.WstxOutputProperties.P_ADD_SPACE_AFTER_EMPTY_ELEM, true);
|
||||||
|
XMLStreamWriter serializer = new IndentingXMLStreamWriter(factory.createXMLStreamWriter(writer));
|
||||||
|
write(serializer, dom);
|
||||||
|
serializer.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void write(PrintWriter writer, XmlNode dom) {
|
public static void write(XMLStreamWriter xmlWriter, XmlNode dom) throws XMLStreamException {
|
||||||
write(new PrettyPrintXMLWriter(writer), dom);
|
xmlWriter.writeStartElement(dom.getPrefix(), dom.getName(), dom.getNamespaceUri());
|
||||||
}
|
|
||||||
|
|
||||||
public static void write(XMLWriter xmlWriter, XmlNode dom) {
|
|
||||||
write(xmlWriter, dom, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void write(XMLWriter xmlWriter, XmlNode dom, boolean escape) {
|
|
||||||
// TODO: move to XMLWriter?
|
|
||||||
xmlWriter.startElement(dom.getName());
|
|
||||||
for (Map.Entry<String, String> attr : dom.getAttributes().entrySet()) {
|
for (Map.Entry<String, String> attr : dom.getAttributes().entrySet()) {
|
||||||
xmlWriter.addAttribute(attr.getKey(), attr.getValue());
|
xmlWriter.writeAttribute(attr.getKey(), attr.getValue());
|
||||||
}
|
}
|
||||||
for (XmlNode aChildren : dom.getChildren()) {
|
for (XmlNode aChildren : dom.getChildren()) {
|
||||||
write(xmlWriter, aChildren, escape);
|
write(xmlWriter, aChildren);
|
||||||
}
|
}
|
||||||
|
|
||||||
String value = dom.getValue();
|
String value = dom.getValue();
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
if (escape) {
|
xmlWriter.writeCharacters(value);
|
||||||
xmlWriter.writeText(value);
|
}
|
||||||
} else {
|
xmlWriter.writeEndElement();
|
||||||
xmlWriter.writeMarkup(value);
|
}
|
||||||
}
|
|
||||||
|
static class IndentingXMLStreamWriter extends StreamWriterDelegate {
|
||||||
|
|
||||||
|
int depth = 0;
|
||||||
|
boolean hasChildren = false;
|
||||||
|
boolean anew = true;
|
||||||
|
|
||||||
|
IndentingXMLStreamWriter(XMLStreamWriter parent) {
|
||||||
|
super(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
xmlWriter.endElement();
|
@Override
|
||||||
|
public void writeStartDocument() throws XMLStreamException {
|
||||||
|
super.writeStartDocument();
|
||||||
|
anew = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeStartDocument(String version) throws XMLStreamException {
|
||||||
|
super.writeStartDocument(version);
|
||||||
|
anew = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeStartDocument(String encoding, String version) throws XMLStreamException {
|
||||||
|
super.writeStartDocument(encoding, version);
|
||||||
|
anew = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeEmptyElement(String localName) throws XMLStreamException {
|
||||||
|
indent();
|
||||||
|
super.writeEmptyElement(localName);
|
||||||
|
hasChildren = true;
|
||||||
|
anew = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeEmptyElement(String namespaceURI, String localName) throws XMLStreamException {
|
||||||
|
indent();
|
||||||
|
super.writeEmptyElement(namespaceURI, localName);
|
||||||
|
hasChildren = true;
|
||||||
|
anew = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeEmptyElement(String prefix, String localName, String namespaceURI) throws XMLStreamException {
|
||||||
|
indent();
|
||||||
|
super.writeEmptyElement(prefix, localName, namespaceURI);
|
||||||
|
hasChildren = true;
|
||||||
|
anew = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeStartElement(String localName) throws XMLStreamException {
|
||||||
|
indent();
|
||||||
|
super.writeStartElement(localName);
|
||||||
|
depth++;
|
||||||
|
hasChildren = false;
|
||||||
|
anew = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeStartElement(String namespaceURI, String localName) throws XMLStreamException {
|
||||||
|
indent();
|
||||||
|
super.writeStartElement(namespaceURI, localName);
|
||||||
|
depth++;
|
||||||
|
hasChildren = false;
|
||||||
|
anew = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeStartElement(String prefix, String localName, String namespaceURI) throws XMLStreamException {
|
||||||
|
indent();
|
||||||
|
super.writeStartElement(prefix, localName, namespaceURI);
|
||||||
|
depth++;
|
||||||
|
hasChildren = false;
|
||||||
|
anew = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeEndElement() throws XMLStreamException {
|
||||||
|
depth--;
|
||||||
|
if (hasChildren) {
|
||||||
|
indent();
|
||||||
|
}
|
||||||
|
super.writeEndElement();
|
||||||
|
hasChildren = true;
|
||||||
|
anew = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void indent() throws XMLStreamException {
|
||||||
|
if (!anew) {
|
||||||
|
super.writeCharacters("\n");
|
||||||
|
}
|
||||||
|
for (int i = 0; i < depth; i++) {
|
||||||
|
super.writeCharacters(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue