我希望有人能指出我在这里遗漏的明显事物。我觉得我已经这样做了一百次,并且由于某种原因,今晚,这种行为让我陷入了困境。
我正在从公共API读取一些XML。我想从某个节点('body'中的所有内容)中提取所有文本,其中还包括各种子节点。简单的例子:
<xml>
<metadata>
<article>
<body>
<sec>
<title>A Title</title>
<p>
This contains
<italic>italics</italic>
and
<xref ref-type="bibr">xref's</xref>
.
</p>
</sec>
<sec>
<title>Second Title</title>
</sec>
</body>
</article>
</metadata>
</xml>
所以最终我想遍历所需节点内的树(再次,'body')并提取其自然顺序中包含的所有文本。很简单,所以我只写了这个小的Groovy脚本......
def xmlParser = new XmlParser()
def xml = xmlParser.parseText(rawXml)
xml.metadata.article.body[0].depthFirst().each { node ->
if(node.children().size() == 1) {
println node.text()
}
}
...继续炸毁“没有方法签名:java.lang.String.children()”。所以我在想自己“等等,什么?我会发疯吗?” Node.depthFirst()应该只返回一个Node的List。我添加了一个'instanceof'检查,果然,我得到了Node对象和String对象的组合。具体而言,不在同一行中的实体内的行将作为String返回,即“This contains”和“and”。其他一切都是节点(如预期的那样)。
我可以轻松解决这个问题。然而,这似乎不是正确的行为,我希望有人可以指出我正确的方向。
答案 0 :(得分:7)
我很确定这是正确的行为(虽然我总是发现XmlSlurper和XmlParser有棘手的API)。你可以迭代的所有东西都应该实现一个节点接口IMO,并且可能有一个type
TEXT
,你可以用来知道从它们获取文本。
这些文本节点是有效的节点,在许多情况下,您需要点击它,因为它首先通过XML进行深度遍历。如果它们没有被返回,那么检查子项大小为1的算法是否会起作用,因为某些节点(如<p>
标签)下面都有混合文本和元素。
另外,为什么depthFirst
不能始终返回文本是唯一子节点的所有文本节点,例如上面的italic
,会使事情变得更糟。
我倾向于使用groovy方法的签名来让运行时找出处理每个节点的正确方法(而不是像instanceof
这样使用):
def rawXml = """<xml>
<metadata>
<article>
<body>
<sec>
<title>A Title</title>
<p>
This contains
<italic>italics</italic>
and
<xref ref-type="bibr">xref's</xref>
.
</p>
</sec>
<sec>
<title>Second Title</title>
</sec>
</body>
</article>
</metadata>
</xml>"""
def processNode(String nodeText) {
return nodeText
}
def processNode(Object node) {
if(node.children().size() == 1) {
return node.text()
}
}
def xmlParser = new XmlParser()
def xml = xmlParser.parseText(rawXml)
def xmlText = xml.metadata.article.body[0].'**'.findResults { node ->
processNode(node)
}
println xmlText.join(" ")
打印
A Title This contains italics and xref's . Second Title
或者,XmlSlurper
类可能会执行您希望/期望的更多内容,并且具有text()
方法的更合理的输出集。如果你真的不需要对结果进行任何类型的DOM行走(XmlParser
更好“),我建议XmlSlurper
:
def xmlParser = new XmlSlurper()
def xml = xmlParser.parseText(rawXml)
def bodyText = xml.metadata.article.body[0].text()
println bodyText
打印:
A Title
This contains
italics
and
xref's
.
Second Title