Ruby 如何在Nokogiri中收集节点的几个元素中的第一个元素
我有如下数据:Ruby 如何在Nokogiri中收集节点的几个元素中的第一个元素,ruby,xml,nokogiri,Ruby,Xml,Nokogiri,我有如下数据: <release> <artists> <artist> <name>Johnny Mnemonic</name> </artist> <artist> <name>Constantine</name> </artist> <artists> </release> <release> &l
<release>
<artists>
<artist>
<name>Johnny Mnemonic</name>
</artist>
<artist>
<name>Constantine</name>
</artist>
<artists>
</release>
<release>
<artists>
<artist>
<name>Speed</name>
</artist>
<artist>
<name>The Matrix</name>
</artist>
<artists>
</release>
...and so on.
xpath表达式选择的是
,而不是像预期的那样选择每个
标记。请尝试以下操作:
doc.search('artists artist').map(&:text)
您的表达式
“//artists”
将检索所有的“artists”标记,[1]
选择这些标记中的第一个,而不是标记本身内部的第一个元素。Nokogiri支持两种主要的搜索类型,搜索
和at
<代码>搜索返回一个节点集,您应该将其视为一个数组at
返回一个节点。可以采用CSS或XPath表达式。我更喜欢CSS,因为它们更具可读性,但有时你不能很容易地找到你想要的位置,所以试试另一个
对于您的问题,使用text
指定要从中提取文本的节点非常重要。如果结果太宽,除了所需标记内的文本外,还将从标记之间获得文本。要避免深入到最直接的节点以了解您要读取的内容,请执行以下操作:
require 'nokogiri'
doc = Nokogiri::XML(<<EOT)
<release>
<artists>
<artist>
<name>Johnny Mnemonic</name>
</artist>
<artist>
<name>Constantine</name>
</artist>
<artists>
<release>
EOT
这些搜索比较松散,因此会返回更多垃圾邮件:
doc.at('artist').text # => "\n Johnny Mnemonic\n "
doc.at('artists').text # => "\n \n Johnny Mnemonic\n \n \n Constantine\n \n \n\n"
使用search
返回多个节点:
doc.search('name').map(&:text)
[
[0] "Johnny Mnemonic",
[1] "Constantine"
]
doc.search('artist').map(&:text)
[
[0] "\n Johnny Mnemonic\n ",
[1] "\n Constantine\n "
]
search
和at
之间唯一的真正区别是at
就像search(…)。首先
另见“”一节
为了方便起见,Nokogiri还有一些额外的别名:at_css
和css
,以及at_xpath
和xpath
以下是从Pry截取的使用CSS和XPath访问器获取名称的替代方法:
[5] (pry) main: 0> # using CSS with Ruby
[6] (pry) main: 0> artists = doc.search('release').map{ |release| release.at('artist').text.strip }
[
[0] "Johnny Mnemonic",
[1] "Speed"
]
[7] (pry) main: 0> # using CSS with less Ruby
[8] (pry) main: 0> artists = doc.search('release artists artist:nth-child(1) name').map{ |n| n.text }
[
[0] "Johnny Mnemonic",
[1] "Speed"
]
[9] (pry) main: 0>
[10] (pry) main: 0> # using XPath
[11] (pry) main: 0> artists = doc.search('release/artists/artist[1]/name').map{ |t| t.content }
[
[0] "Johnny Mnemonic",
[1] "Speed"
]
[12] (pry) main: 0> # using more XPath
[13] (pry) main: 0> artists = doc.search('release/artists/artist[1]/name/text()').map{ |t| t.content }
[
[0] "Johnny Mnemonic",
[1] "Speed"
]
page.xpath(“release/artists/artist”)。首先
?非常感谢。我想要的似乎是医生的名字。还有一个问题,你能告诉我如何在每个节点上重复吗?啊。你没有给我们一个准确的数据例子<代码>“名称”不考虑任何包含的节点。
是否重要,导致您中断并为每个人做一些特殊的事情?根据我给你的信息,你应该能找到答案。对不起。Release是第一个节点,其余节点都作为子节点。我想从每个版本中提取第一个“名称”数据,其中可能有10000个。因此,您的代码从第一个发行版节点中提取了第一个名称,我希望在每个版本中重复该操作,并且以与第一个版本相同的方式进行结构。同样,您的示例数据需要显示这一点。请加一个准确的例子。减少它,但它需要显示您将使用什么。对代码的修复很容易,但我想做一次更改,而不是在源数据显示出更多更改时一次又一次地进行更改。抱歉,代码已编辑。这是两个版本的示例,其中将有数千个版本。我想从每个节点提取第一个“名称”数据。
doc.search('name').map(&:text)
[
[0] "Johnny Mnemonic",
[1] "Constantine"
]
doc.search('artist').map(&:text)
[
[0] "\n Johnny Mnemonic\n ",
[1] "\n Constantine\n "
]
[5] (pry) main: 0> # using CSS with Ruby
[6] (pry) main: 0> artists = doc.search('release').map{ |release| release.at('artist').text.strip }
[
[0] "Johnny Mnemonic",
[1] "Speed"
]
[7] (pry) main: 0> # using CSS with less Ruby
[8] (pry) main: 0> artists = doc.search('release artists artist:nth-child(1) name').map{ |n| n.text }
[
[0] "Johnny Mnemonic",
[1] "Speed"
]
[9] (pry) main: 0>
[10] (pry) main: 0> # using XPath
[11] (pry) main: 0> artists = doc.search('release/artists/artist[1]/name').map{ |t| t.content }
[
[0] "Johnny Mnemonic",
[1] "Speed"
]
[12] (pry) main: 0> # using more XPath
[13] (pry) main: 0> artists = doc.search('release/artists/artist[1]/name/text()').map{ |t| t.content }
[
[0] "Johnny Mnemonic",
[1] "Speed"
]