【问题标题】:Parsing an XML file with Nokogiri to determine the path (Ruby)使用 Nokogiri 解析 XML 文件以确定路径(Ruby)
【发布时间】:2013-03-19 09:19:40
【问题描述】:

我的代码应该“猜测”位于我的 XML 文件中相关文本节点之前的路径。在这种情况下,相关意味着:文本节点嵌套在重复出现的产品/人/某事标签内,但不是在它之外使用的文本节点。

这段代码:

    @doc, items = Nokogiri.XML(@file), []

    path = []
    @doc.traverse do |node|
      if node.class.to_s == "Nokogiri::XML::Element"
        is_path_element = false
        node.children.each do |child|
          is_path_element = true if child.class.to_s == "Nokogiri::XML::Element"
        end
        path.push(node.name) if is_path_element == true && !path.include?(node.name)
      end
    end
    final_path = "/"+path.reverse.join("/")

适用于简单的 XML 文件,例如:

<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
  <channel>
    <title>Some XML file title</title>
    <description>Some XML file description</description>
    <item>
      <title>Some product title</title>
      <brand>Some product brand</brand>
    </item>
    <item>
      <title>Some product title</title>
      <brand>Some product brand</brand>
    </item>
  </channel>
</rss>

puts final_path # => "/rss/channel/item"

但是当事情变得更加复杂时,我应该如何应对挑战?比如这个:

<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
  <channel>
    <title>Some XML file title</title>
    <description>Some XML file description</description>
    <item>
      <titles>
        <title>Some product title</title>
      </titles>
      <brands>
        <brand>Some product brand</brand>
      </brands>
    </item>
    <item>
      <titles>
        <title>Some product title</title>
      </titles>
      <brands>
        <brand>Some product brand</brand>
      </brands>
    </item>
  </channel>
</rss>

【问题讨论】:

  • 不确定我是否理解 - 第二个 XML 示例的分析应该会产生什么,为什么?您的代码似乎构造了一个路径(可能不存在),其中包含任何具有子元素的内容。 . .
  • 嗨,尼尔。我的假设是位于最深层的文本节点必须是相关的。所以代码应该确定通向最深嵌套文本节点的路径。为什么确定的路径不应该存在?
  • 对不起,我忘了回答第一个问题:我不确定第二个 XML 的分析应该产生什么。多条路径,例如“/rss/channel/item/titles” + “/rss/channel/item/brands”,或者一些正则表达式,例如/\/rss\/channel\/item\/.*/
  • 如果你有两个同样深的结构(例如 /rss/channel/item 路径有孩子,你的第一个文件中有 /rss/channel/owner,两者都会被添加到你的数组中,您会看到类似“/rss/channel/item/owner”的内容
  • 如果我接受“我的假设是位于最深层的文本节点必须是相关的。” - 给你一些列出最深结构的容器的东西会很简单,你的代码只需要稍作改动。你确定这是你现阶段想要的吗?

标签: ruby xpath xml-parsing nokogiri


【解决方案1】:

如果您正在寻找 XML 中最深的“父”路径列表,有不止一种方法可以查看。

虽然我认为可以调整您自己的代码以实现相同的输出,但我确信使用 xpath 可以实现相同的目标。我的动机是让我的 XML 技能不生锈(还没有使用 Nokogiri,但我很快就需要专业地这样做)。因此,这里是如何使用 xpath 获取所有在其下只有一个子级别的父路径:

xml.xpath('//*[child::* and not(child::*/*)]').each { |node| puts node.path }

第二个示例文件的输出是:

/rss/channel/item[1]/titles
/rss/channel/item[1]/brands
/rss/channel/item[2]/titles
/rss/channel/item[2]/brands

。 . .如果你取出这个列表并 gsub 出索引,然后使数组唯一,那么这看起来很像你的循环的输出。 . .

paths = xml.xpath('//*[child::* and not(child::*/*)]').map { |node| node.path }
paths.map! { |path| path.gsub(/\[[0-9]+\]/,'') }.uniq!
=> ["/rss/channel/item/titles", "/rss/channel/item/brands"]

或者在一行中:

paths = xml.xpath('//*[* and not(*/*)]').map { |node| node.path.gsub(/\[[0-9]+\]/,'') }.uniq
=> ["/rss/channel/item/titles", "/rss/channel/item/brands"]

【讨论】:

  • 那是我见过的最美的。非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-20
  • 2021-05-03
  • 2023-04-01
相关资源
最近更新 更多