如何打印带有命名空间的 Groovy 节点?

5
当我使用这段代码来输出一些我用XmlParser解析(并修改)过的XML时:
XmlParser parser = new XmlParser()
def root = parser.parseText(feedUrl.toURL().text)
def writer = new StringWriter()
new XmlNodePrinter(new PrintWriter(writer)).print(root)
println writer.toString()

即使根节点上存在命名空间声明,它们在roottoString()中不会被打印出来... 有什么想法吗?

2个回答

4
我刚刚遇到了同样的问题,经过一番摆弄后,我找到了一个解决方法。您可以使用 XmlSluper 而不是 XmlParser,并使用 StreamingMarkupBuilder 而不是 XmlNodePrinter。然后,利用 bind 中的闭包,并使用内置变量 mkp 声明命名空间。
例如,使用 Ted 上面提供的源 XML 示例:
def root = new XmlSlurper().parseText("http://stackoverflow.com/feeds/question/227447".toURL().text))
def outputBuilder = new StreamingMarkupBuilder()
String result = XmlUtil.serialize(outputBuilder.bind {
    mkp.declareNamespace('':'http://www.w3.org/2005/Atom')
    mkp.declareNamespace('creativeCommons':'http://backend.userland.com/creativeCommonsRssModule')
    mkp.declareNamespace('re':'http://purl.org/atompub/rank/1.0')
    mkp.yield root }
)
println result

结果为:

<?xml version="1.0" encoding="UTF-8"?><feed xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" xmlns="http://www.w3.org/2005/Atom" xmlns:re="http://purl.org/atompub/rank/1.0">
<title type="text">How do I print a groovy Node with namespace preserved? - Stack Overflow </title>
<link rel="self" type="application/atom+xml" href="http://stackoverflow.com/feeds/question/227447"/>
<link rel="alternate" type="text/html" href="https://dev59.com/_0XRa4cB1Zd3GeqPs5Th"/>
<subtitle>most recent 30 from stackoverflow.com</subtitle>
<updated>2011-02-16T05:13:17Z</updated>
<id>http://stackoverflow.com/feeds/question/227447</id>
<creativeCommons:license>http://www.creativecommons.org/licenses/by-nc/2.5/rdf</creativeCommons:license>
<entry>
<id>https://dev59.com/_0XRa4cB1Zd3GeqPs5Th
<re:rank scheme="http://stackoverflow.com">2</re:rank>

1

看起来它正在对输出进行非规范化处理,并将命名空间上下文与实际需要命名空间上下文的节点一起包含。

例如,此问题的网页带有内嵌CreativeCommons命名空间:

<feed xmlns="http://www.w3.org/2005/Atom" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" xmlns:thr="http://purl.org/syndication/thread/1.0">
  <!-- snip -->
  <creativeCommons:license>http://www.creativecommons.org/licenses/by-nc/2.5/rdf</creativeCommons:license>
  <!-- snip -->
</feed>

当您使用此脚本输出xml时:

def root = new XmlParser().parseText("http://stackoverflow.com/feeds/question/227447".toURL().text)
println new XmlNodePrinter().print(root)

最终将命名空间移动到需要该命名空间的许可证节点。在这种情况下,这并不是什么大问题,因为该命名空间中只有一个节点。如果大多数XML都使用了命名空间,那么它可能会使事情变得更加臃肿。

<feed xmlns="http://www.w3.org/2005/Atom">
  <!-- snip -->
    <creativeCommons:license xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule">
http://www.creativecommons.org/licenses/by-nc/2.5/rdf
  </creativeCommons:license>
  <!-- snip -->
</feed>

如果您真的想要规范化节点,您需要对XmlNodePrinter进行一些调整,以便通过XML进行两次遍历,第一次收集所有使用的命名空间,第二次在顶部输出它们,而不是在每个命名空间节点内部输出。Groovy源代码实际上非常易读,如果您确实需要这样做,修改起来并不难。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接