使用Nokogiri从XML获取低级xpath

时间:2014-05-20 00:25:59

标签: ruby xpath nokogiri

我正在尝试在数组中存储下面XML中低级元素的所有唯一Xpath,但就像我在数组中一样,存储所有XML,而不仅仅是Xpath本身。 XML具有不同级别的Xpath。我的意思是,一些子元素只有2个祖先,而其他元素不止一个。

这是我的代码。

require 'nokogiri'
doc = Nokogiri::XML(<<EOT)

<?xml version="1.0" encoding="UTF-8"?>
<items>
    <item>
        <name>Cake</name>
        <ppu>0.55</ppu>
        <batters>
            <batter>Regular</batter>
            <batter>Chocolate</batter>
            <batter>Blueberry</batter>
            <batter>Devil's Food</batter>
        </batters>
        <topping>None</topping>
        <topping>Glazed</topping>
        <topping>Sugar</topping>
        <topping>Powdered Sugar</topping>
        <topping>Chocolate with Sprinkles</topping>
        <topping>Chocolate</topping>
        <topping>Maple</topping>
    </item>
    <item>
        <name>Raised</name>
        <ppu>0.55</ppu>
        <batters>
            <batter>Regular</batter>
        </batters>
        <topping>None</topping>
        <topping>Glazed</topping>
        <topping>Sugar</topping>
        <topping>Chocolate</topping>
        <topping>Maple</topping>
    </item>
</items>
EOT

a = []
a = doc.xpath("//*")

puts a

我想在数组“a”中存储唯一的xpath,如下所示:

/items/item/name
/items/item/ppu
/items/item/batters/batter
/items/item/topping

也许有人可以帮我解决这个问题。

感谢您的帮助。

1 个答案:

答案 0 :(得分:2)

您想要选择的是&#34; leaf&#34;节点。你可以这样做:

doc.xpath("//*[not(*)]")

这意味着&#34;选择所有不包含元素的元素&#34;。

如果您需要XPath,则需要在每个节点上调用.path。但Nokogiri提供的路径有明确的位置(例如/items/item[2]/topping[4]),因此您必须应用正则表达式删除它们,然后使用uniq删除重复项:

doc.xpath("//*[not(*)]").map {|leaf| leaf.path.gsub(/\[.*?\]/, '') }.uniq

输出:

/items/item/name
/items/item/ppu
/items/item/batters/batter
/items/item/topping