获得属性的价值并使用Nokogiri进行测试

时间:2016-12-16 15:21:46

标签: ruby xml xpath nokogiri

我有一个XML转储,我试图用Nokogiri解析它以获取属性的文本值,然后找出它是否与我正在寻找的某个字符串匹配。这是我的XML文件的片段:

      #(Element:0x3fc58cc091f8 {
      name = "host",
      attributes = [ #(Attr:0x3fc58cc08528 { name = "starttime", value = "1481896934" }), #(Attr:0x3fc58cc08514 { name = "endtime", value = "1481896947" })],
      children = [
        #(Element:0x3fc58af6bdc0 {
          name = "status",
          attributes = [
            #(Attr:0x3fc58af6b6f4 { name = "state", value = "up" }),
            #(Attr:0x3fc58af6b6e0 { name = "reason", value = "arp-response" }),
            #(Attr:0x3fc58af6b6cc { name = "reason_ttl", value = "0" })]
          }),
        #(Text "\n"),
        #(Element:0x3fc58a744fe8 {
          name = "os",
          children = [
            #(Element:0x3fc58c1392f0 {
              name = "osmatch",
              attributes = [
                #(Attr:0x3fc58c1381d4 { name = "name", value = "Microsoft Windows XP SP2 or SP3, or Windows Server 2003" }),
                #(Attr:0x3fc58c1381c0 { name = "accuracy", value = "100" }),
                #(Attr:0x3fc58c1381ac { name = "line", value = "57766" })],
              children = [
                #(Text "\n"),
                #(Element:0x3fc58ae89e70 {
                  name = "osclass",
                  attributes = [
                    #(Attr:0x3fc58ae893bc { name = "type", value = "general purpose" }),
                    #(Attr:0x3fc58ae893a8 { name = "vendor", value = "Microsoft" }),
                    #(Attr:0x3fc58ae89394 { name = "osfamily", value = "Windows" }),
                    #(Attr:0x3fc58ae89380 { name = "osgen", value = "XP" }),
                    #(Attr:0x3fc58ae8936c { name = "accuracy", value = "100" })],
                  children = [ #(Element:0x3fc58b19428c { name = "cpe", children = [ #(Text "cpe:/o:microsoft:windows_xp")] })]
                  }),
                #(Text "\n"),

所以,我尝试做的是获取os/osmatch/@name.value的内容。在这种情况下,它将是Windows XP SP2 or SP3, or Windows Server 2003

我已经把那部分放下了:

 doc.xpath("//host").each do |host|
   os = host.at_xpath("os/osmatch").at_xpath("@name").value rescue nil
 end

 output: Microsoft Windows XP SP2 or SP3, or Windows Server 2003

通常,我的XML文件将拥有大量具有不同操作系统的主机,因此输出可能类似于:

 Microsoft Windows XP SP2 or SP3, or Windows Server 2003
 Ubuntu 14.04 Linux
 Microsoft Windows 7, or Microsoft Windows 8
 FreeBSD X.X.X
 ....

我尝试做的是将某些字符串与我现在正在寻找的值匹配,因此如果找到Windows XP,我可以采取一些措施。

 doc.xpath("//host").each do |host|
   os = host.at_xpath("os/osmatch").at_xpath("@name[contains(value, 'Windows XP')]")
 end

但相反,我收到了错误,所以我知道我做错了什么。我尝试过其他一些变体,但无法弄清楚如何做到这一点:

 Nokogiri::XML::XPath::SyntaxError: Invalid expression: @name[contains(value, 'Windows']

2 个答案:

答案 0 :(得分:1)

您似乎在混淆Xpath和Ruby代码。您的工作代码是

at_xpath("@name").value

这里@name是XPath查询,这会向Ruby返回一个Node对象。此对象具有value方法,该方法以字符串形式返回属性的值,但value 有效的XPath。

您尝试通过添加谓词来更改此内容:

at_xpath("@name[contains(value, 'Windows XP')]")

在这里,您尝试在XPath中使用Ruby value方法。这不起作用。但是,在XPath中,您可以使用.(即点)来选择当前节点,这就是您想要的:

at_xpath("@name[contains(., 'Windows XP')]")

如果它包含字符串“Windows XP”,这将为您提供当前节点的name属性(您正在调用at_xpath的内容)。

答案 1 :(得分:0)

host.at_xpath("os/osmatch[contains(@name,'Windows')]")