首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用XmlSlurper:如何在迭代GPathResult时选择子元素

使用XmlSlurper:如何在迭代GPathResult时选择子元素
EN

Stack Overflow用户
提问于 2009-11-04 17:51:08
回答 3查看 11.2K关注 0票数 8

我正在编写一个HTML解析器,它使用TagSoup将格式良好的结构传递给XMLSlurper。

以下是通用代码:

代码语言:javascript
复制
def htmlText = """
<html>
<body>
<div id="divId" class="divclass">
<h2>Heading 2</h2>
<ol>
<li><h3><a class="box" href="#href1">href1 link text</a> <span>extra stuff</span></h3><address>Here is the address<span>Telephone number: <strong>telephone</strong></span></address></li>
<li><h3><a class="box" href="#href2">href2 link text</a> <span>extra stuff</span></h3><address>Here is another address<span>Another telephone: <strong>0845 1111111</strong></span></address></li>
</ol>
</div>
</body>
</html>
"""     

def html = new XmlSlurper(new org.ccil.cowan.tagsoup.Parser()).parseText( htmlText );

html.'**'.grep { it.@class == 'divclass' }.ol.li.each { linkItem ->
    def link = linkItem.h3.a.@href
    def address = linkItem.address.text()
    println "$link: $address\n"
}

我希望每个人都允许我依次选择每一个“li”,这样我就可以检索相应的href和地址细节。相反,我得到了这个输出:

代码语言:javascript
复制
#href1#href2: Here is the addressTelephone number: telephoneHere is another addressAnother telephone: 0845 1111111

我检查了web上的各种示例,这些示例要么处理XML,要么是单行示例,如“从该文件检索所有链接”。看起来,it.h3.a.@href表达式正在收集文本中的所有href,即使我将它传递给父节点'li‘节点。

你能告诉我:

  • 为什么我要让输出显示
  • 如何检索每个'li‘项

的href/address对

谢谢。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2009-11-05 05:48:18

将grep改为“查找”:

代码语言:javascript
复制
html.'**'.find { it.@class == 'divclass' }.ol.li.each { linkItem ->
    def link = linkItem.h3.a.@href
    def address = linkItem.address.text()
    println "$link: $address\n"
}

然后你就会得到

代码语言:javascript
复制
#href1: Here is the addressTelephone number: telephone

#href2: Here is another addressAnother telephone: 0845 1111111

grep返回一个ArrayList,但find返回一个NodeChild类:

代码语言:javascript
复制
println html.'**'.grep { it.@class == 'divclass' }.getClass()
println html.'**'.find { it.@class == 'divclass' }.getClass()

在以下方面的成果:

代码语言:javascript
复制
class java.util.ArrayList
class groovy.util.slurpersupport.NodeChild

因此,如果您想使用grep,那么您可以嵌套另一个这样的,这样它才能工作。

代码语言:javascript
复制
html.'**'.grep { it.@class == 'divclass' }.ol.li.each {
    it.each { linkItem ->
        def link = linkItem.h3.a.@href
        def address = linkItem.address.text()
        println "$link: $address\n"
    }
}

长话短说,在您的情况下,使用查找而不是grep。

票数 11
EN

Stack Overflow用户

发布于 2013-04-25 16:12:09

这是个棘手的问题。当只有一个带有class='divclass‘的元素时,前面的答案肯定是好的。如果grep有多个结果,那么一个结果的find()就不是答案。指出结果是ArrayList是正确的。插入外部嵌套的.each()循环将在闭包参数div中提供一个GPathResult。从这里开始,向下钻可以按照预期的结果继续下去。

代码语言:javascript
复制
html."**".grep { it.@class == 'divclass' }.each { div -> div.ol.li.each { linkItem ->
   def link = linkItem.h3.a.@href
   def address = linkItem.address.text()
   println "$link: $address\n"
}}

原始代码的行为也可以使用更多的解释。当在Groovy中的列表上访问一个属性时,您将得到一个新的列表(大小相同),其中包含列表中每个元素的属性。grep()找到的列表只有一个条目。然后我们得到一个关于属性ol的条目,这很好。接下来,我们得到该条目的ol.it结果。它还是size() == 1的列表,但是这次是size() == 2的条目。

代码语言:javascript
复制
html."**".grep { it.@class == 'divclass' }.ol.li.each { it.each { linkItem ->
   def link = linkItem.h3.a.@href
   def address = linkItem.address
   println "$link: $address\n"
}}

在任何表示多个节点的GPathResult上,我们都会得到所有文本的连接。这是最初的结果,首先是@href,然后是address。

票数 1
EN

Stack Overflow用户

发布于 2015-03-02 00:36:09

我相信在撰写本报告时,前面的答案都是正确的,因为使用的版本是正确的。但是,我在Groovy2.3.7中使用了HTTPBuilder 0.7.1和Grails 2.4.4,并且存在一个大问题-- HTML元素被转换为大写。似乎是由于它下面使用的NekoHTML:

http://nekohtml.sourceforge.net/faq.html#uppercase

因此,所接受的答案中的解决方案必须写成:

代码语言:javascript
复制
html.'**'.find { it.@class == 'divclass' }.OL.LI.each { linkItem ->
    def link = linkItem.H3.A.@href
    def address = linkItem.ADDRESS.text()
    println "$link: $address\n"
}

这是非常令人沮丧的调试,希望它能帮助到某人。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1675542

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档