ruby-on-rails - 如何使用 Nokogiri 访问嵌套的 XML
问题描述
我正在使用 Nokogiri 解析 XML。有人告诉我使用 CSS 选择器来搜索 XML,但我无法将其链接到嵌套对象中。
如何访问内部元素?
2.6.3 :039 > pp a.css("interface").to_s
"<interface>\n" +
" <status>\n" +
" <__XML__OPT_Cmd_show_interface_status_down>\n" +
" <__XML__OPT_Cmd_show_interface_status___readonly__>\n" +
" <__readonly__>\n" +
" <TABLE_interface>\n" +
" <ROW_interface>\n" +
" <interface>mgmt0</interface>\n" +
" <state>connected</state>\n" +
" <vlan>routed</vlan>\n" +
" <duplex>full</duplex>\n" +
" <speed>a-1000</speed>\n" +
" <type>--</type>\n" +
" </ROW_interface>\n" +
" <ROW_interface>\n" +
" <interface>Vlan1</interface>\n" +
" <state>down</state>\n" +
" <vlan>routed</vlan>\n" +
" <duplex>auto</duplex>\n" +
" <speed>auto</speed>\n" +
" </ROW_interface>\n" +
" <ROW_interface>\n" +
" <interface>Vlan6</interface>\n" +
" <state>down</state>\n" +
" <vlan>routed</vlan>\n" +
" <duplex>auto</duplex>\n" +
" <speed>auto</speed>\n" +
" </ROW_interface>\n" +
" <ROW_interface>\n" +
" <interface>Vlan486</interface>\n" +
" <state>down</state>\n" +
" <vlan>routed</vlan>\n" +
" <duplex>auto</duplex>\n" +
" <speed>auto</speed>\n" +
" </ROW_interface>\n" +
" </TABLE_interface>\n" +
" </__readonly__>\n" +
" </__XML__OPT_Cmd_show_interface_status___readonly__>\n" +
" </__XML__OPT_Cmd_show_interface_status_down>\n" +
" </status>\n" +
" </interface><interface>mgmt0</interface><interface>Vlan1</interface><interface>Vlan6</interface><interface>Vlan486</interface>"
我最终得到了这棵树。我的 XPath 是什么?这只是解析的 XML 的一部分:
2.6.3 :043 > pp parsed
#(DocumentFragment:0x3fce080cd300 {
name = "#document-fragment",
children = [
#(ProcessingInstruction:0x3fce080cce14 { name = "xml" }),
#(Text "\n"),
#(Element:0x3fce080cc7d4 {
name = "rpc-reply",
namespace = #(Namespace:0x3fce080cffb0 {
prefix = "nf",
href = "urn:ietf:params:xml:ns:netconf:base:1.0"
}),
children = [
#(Text "\n" + " "),
#(Element:0x3fce080cf22c {
name = "data",
namespace = #(Namespace:0x3fce080cffb0 {
prefix = "nf",
href = "urn:ietf:params:xml:ns:netconf:base:1.0"
}),
children = [
#(Text "\n" + " "),
#(Element:0x1903f98 {
name = "show",
namespace = #(Namespace:0x1903f20 {
href = "http://www.cisco.com/nxos:1.0:if_manager"
}),
children = [
#(Text "\n" + " "),
#(Element:0x1903700 {
name = "interface",
namespace = #(Namespace:0x1903f20 {
href = "http://www.cisco.com/nxos:1.0:if_manager"
}),
children = [
#(Text "\n" + " "),
#(Element:0x19030fc {
name = "status",
namespace = #(Namespace:0x1903f20 {
href = "http://www.cisco.com/nxos:1.0:if_manager"
}),
children = [
#(Text "\n" + " "),
#(Element:0x1902a1c {
name = "__XML__OPT_Cmd_show_interface_status_down",
namespace = #(Namespace:0x1903f20 {
href = "http://www.cisco.com/nxos:1.0:if_manager"
}),
解决方案
你的问题真的很笼统,而且问得不好,所以不可能回答一个特定的问题,但看起来你需要了解如何使用 CSS 访问器访问文档中的标签,这让 Nokogiri 变得非常容易。
沉思于此:
require 'nokogiri'
foo =<<EOT
<tag1>
<tag2>some text</tag2>
<tag3>some more text</tag3>
<tags>something</tags>
<tags>or</tags>
<tags>other</tags>
</tag1>
EOT
xml = Nokogiri::XML.parse(foo)
at
查找文档中的第一个匹配项:
xml.at('tag2').content # => "some text"
at
非常聪明,因为它会尝试确定访问器是 CSS 还是 XPath,因此当您想要第一次匹配时,它是一个很好的第一个工具。如果这不起作用,那么您可以尝试at_css
指定访问器是 CSS,因为有时您可以想出一些可以用作 CSS 或 XPath 但返回不同结果的东西:
xml.at_css('tag3').content # => "some more text"
xml.at_css('tag3').text # => "some more text"
at
与is类似search
,它也尝试确定它是 CSS 还是 XPath,但会查找整个文档中的所有匹配节点,而不仅仅是第一个匹配的节点。因为它返回所有匹配的节点,所以它返回一个 NodeSet,不像at
返回一个 Node,所以你必须知道 NodeSet 在访问它们的content
or时的行为与 Nodes 不同text
:
xml.search('tags').text # => "somethingorother"
这几乎不是您想要的,但是您会惊讶于有多少人问如何将结果字符串拆分为所需的三个单词。通常不可能做到准确,因此需要采用不同的策略:
xml.search('tags').map { |t| t.content } # => ["something", "or", "other"]
xml.search('tags').map { |t| t.text } # => ["something", "or", "other"]
xml.search('tags').map(&:text) # => ["something", "or", "other"]
at
和search
have..._css
和变体都..._xpath
可以帮助您微调代码的行为,但我始终建议从泛型开始at
,search
直到您被迫定义访问器是什么。
我还建议从 XPath 上的 CSS 访问器开始,因为如果您使用 CSS 在 HTML 中工作,它们往往更具可读性,并且更容易学习。XPath 非常强大,可能仍然比 CSS 更强大,但是学习它需要更长的时间,而且通常会导致代码的可读性降低,从而影响可维护性。
这些都在教程、备忘单和文档中。Nokogiri 非常强大,但需要时间阅读和尝试才能学习它。您还可以在 SO 上搜索我写的关于搜索 XML 和 HTML 文档的其他内容;特别是“哪些是使用 Nokogiri 的示例? ”有助于了解如何抓取页面。有很多信息涉及与此相关的许多不同主题。我发现解析这样的文档是一项有趣的练习,因为它多年来一直是我职业生涯的一部分。
推荐阅读
- python - SQL mycursor.execute INSERT 代码使用 python 失败
- npm - 运行 npm install 后如何修复 aws-cdk 的“找不到命令”
- c - 两个链表之间的递归对称差
- c# - 通过忽略错误仅反序列化有效对象
- maven - maven 运行单元测试前需要检查环境
- powershell - 如何停止运行排除文件中指定的服务的多个服务
- c# - 深度链接适用于设备,但不适用于 android 模拟器?
- java - 获取字符串中“EMPTY SPACE”的长度
- python - 拆分和连接二维数组中的元素
- javadoc - 如何包含和链接到外部 javadocs