我正在尝试从XML节点创建格式化的字符串。参见以下示例:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<parent>
<foo>
<bar>foo</bar>
</foo>
</parent>
</root>
我要为其创建格式字符串的节点是“ foo”。我期望这样的结果:
<foo>
<bar>foo</bar>
</foo>
但是实际结果是:
<foo>
<bar>foo</bar>
</foo>
我的方法如下:
public String toXmlString(Node node) throws TransformerException {
final Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
final Writer writer = new StringWriter();
final StreamResult streamResult = new StreamResult(writer);
transformer.transform(new DOMSource(node), streamResult);
return writer.toString();
}
我在做什么错了?
答案 0 :(得分:1)
它确实在做应该做的事情。 indent="yes"
允许转换为 add 空格以缩进元素,但不能删除空格,因为它不知道输入中哪个空格很重要。
在您提供的输入中,<foo>
和</foo>
元素行有8个前导空格,而<bar>
行有12个。
<foo>
开头标记没有缩进的原因是,前面的空格实际上属于包含的<parent>
元素,并且在传递给转换的子树中不存在。
标准(XSLT 1,XSLT 2)中详细介绍了空格剥离行为。总结
如果满足以下任一条件,则保留空白文本节点:
- 文本节点父级的元素名称在保留空白的元素名称集中
- ...
和
(XSLT 2)保留空格的元素名称集由xsl:strip-space和xsl:preserve-space声明指定。元素名称是否包含在保留空白的名称集中,取决于所有xsl:strip-space或xsl:preserve-space声明中的最佳匹配:只有并且不存在匹配或最佳匹配时,才包含该元素名称match是一个xsl:preserve-space元素。
在XSLT 1规范中更简单地陈述:
最初,保留空白的元素名称集包含所有元素名称。
不幸的是,使用xsl:strip-space
不会产生您想要的结果。使用<xsl:strip-space elements="*">
(和indent="yes"
),我得到以下输出:
<foo><bar>foo</bar>
</foo>
有道理。去除空格,然后使</foo>
标签在其开始标签下对齐。
答案 1 :(得分:0)
这将与第三方库JDOM 2更好地配合使用,这也使处理DOM文档的一切变得更容易。
它的“漂亮格式”输出将按预期缩进,从而删除现有的缩进,只要删除/更改的文本节点仅是空格。如果要保留空白,则不需要缩进。
看起来像这样:
public String toXmlString(Element element) {
return new XMLOutputter(Format.getPrettyFormat()).outputString(element);
}
答案 2 :(得分:0)
只要您在输入中去除空格,Saxon就会提供所需的输出:
public void testIndentation() {
try {
String in = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<root>\n"
+ " <parent>\n"
+ " <foo>\n"
+ " <bar>foo</bar>\n"
+ " </foo> \n"
+ " </parent>\n"
+ "</root>";
Processor proc = new Processor(false);
DocumentBuilder builder = proc.newDocumentBuilder();
builder.setWhitespaceStrippingPolicy(WhitespaceStrippingPolicy.ALL); //XX
XdmNode doc = builder.build(new StreamSource(new StringReader(in)));
StringWriter sw = new StringWriter();
Serializer serializer = proc.newSerializer(sw);
serializer.setOutputProperty(Serializer.Property.METHOD, "xml");
serializer.setOutputProperty(Serializer.Property.INDENT, "yes");
XdmNode foo = doc.axisIterator(Axis.DESCENDANT, new QName("foo")).next();
serializer.serializeNode(foo);
System.err.println(sw);
} catch (SaxonApiException err) {
fail();
}
}
但是,如果不删除空格(在第XX行注释),则会在文章中看到输出参差不齐的内容。从XSLT 2.0起,该规范允许处理器比这更智能,但是Saxon没有利用这一优势。一个原因是序列化是完全流式传输的:它孤立地查看每个事件(开始元素,结束元素等),而不是整个文档。
答案 3 :(得分:0)
基于kumesana的答案,我找到了可接受的解决方案:
public String toXmlString(Node node) throws TransformerException {
final DOMBuilder builder = new DOMBuilder();
final Element element = (Element) node;
final org.jdom2.Element jdomElement = builder.build(element);
final XMLOutputter xmlOutputter = new XMLOutputter(Format.getPrettyFormat());
final String output = xmlOutputter.outputString(jdomElement);
return output;
}