关于ruby:基于属性值的Nokogiri条件

Nokogiri condition based on attribute value

我正在尝试使用Nokogiri解析两个XML文件,该文件基于现有的属性值。问题是,即使xpath处不存在该节点,我的初始条件也总是返回true。我认为我做对了所有事情,但显然我没有做。

这是我的两个XML文件:

dnsrecon_output.xml(典型文件输出)

1
2
3
4
5
6
7
8
9
<?xml version="1.0" ?>
<records>
    <record ns_server="192.168.1.1" type="info" zone_transfer="failed"/>
    <record ns_server="192.168.1.2" type="info" zone_transfer="failed"/>
    <record address="192.168.1.1" mname="ns1.mynetwork.local" type="SOA"/>
    <record Version="9.8.2rc1-RedHat-9.8.2-0.37.rc1.el6_7.5" address="192.168.1.1" recursive="True" target="ns1.mynetwork.local" type="NS"/>
    <record Version="9.8.2rc1-RedHat-9.8.2-0.37.rc1.el6_7.5" address="192.168.1.2" recursive="True" target="ns2.mynetwork.local" type="NS"/>
    <record address="192.168.1.3" name="web.local" type="A"/>
</records>

dnsrecon_brute.xml

1
2
3
4
5
6
7
8
9
<?xml version="1.0" ?>
<records>
    <record address="192.168.1.3" name="dev.web.local" type="A"/>
    <record name="ftp.web.local" target="dev.web.local" type="CNAME"/>
    <record address="192.168.1.4" name="git.web.local" type="A"/>
    <record address="192.168.1.5" name="ops.web.local" type="A"/>
    <record address="192.168.1.6" name="whm.web.local" type="A"/>
    <record address="192.168.1.7" name="www.web.local" type="A"/>
</records>

但是,如果zone_transfer=success,输出将如下所示...

dnsrecon_output_xfer.xml(只是为了显示我要匹配的内容)

1
2
3
4
5
6
7
8
9
<?xml version="1.0" ?>
<records>
    <record ns_server="192.168.1.2" type="info" zone_transfer="success"/>
    <record address="192.168.1.2" mname="ns" type="SOA" zone_server="192.168.1.2"/>
    <record address="192.168.1.2" target="ns1.network.local" type="NS" zone_server="192.168.1.2"/>
    <record address="192.168.1.100" name="win.network.local" type="A" zone_server="192.168.1.2"/>
    <record address="192.168.1.2" name="ns1.network.local" type="A" zone_server="192.168.1.2"/>
    <record address="192.168.1.2" mname="ns1.network.local" type="SOA"/>
</records>

这是我的Nokogiri解析。主要是我想检查zone_transfer=success是否存在,如果它不继续移动到*_brute.xml文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
document = Nokogiri::XML(File.open("dnsrecon_output.xml"))

document.remove_namespaces!

# Strictly for Zone transfers
if document.xpath("//records//record[@zone_transfer='success']")
  puts"Zone Transfer Successful ... YIKES!!!"
  document.xpath("//records//record[@type='A']").each do |record|
    # change the output here to match what we need it to...
    puts"#{record.at_xpath("@address")} - #{record.at_xpath("@name")}"
  end
else
  puts"No zone transfers... moving to brute"
  document2 = Nokogiri::XML(File.open("dnsrecon_brute.xml"))
  document2.remove_namespaces!

  document2.xpath("//records//record[@type='A' or @type='CNAME']").each do |record|
    puts"#{record.at_xpath("@address")} - #{record.at_xpath("@name")}"
  end
end

您会注意到,我最初是解析dnsrecon_output.xml文件,该文件在记录标记中具有zone_transfer="failed"。但是,我在控制台中的输出是:

1
2
Zone Transfer Successful ... YIKES!!!
192.168.1.3 - web.local

并且永远不要运行else部分,应该这样做。属性值检查哪里出错了?


您的支票返回空的Nokogiri::XML::NodeSet,这是事实。

读取属性并比较其值:

1
2
if document.xpath("//records//record/@zone_transfer").first.value == 'success'
    ...

请注意,这仅在xpath至少匹配一个元素时才有效(因此,它不适用于" brute"文件)。

或添加any?以获得布尔返回值:

1
2
if document.xpath("//records//record[@zone_transfer='success']").any?
    ...


1
2
3
4
5
x = document.xpath("//records//record[@zone_transfer='success']")
p x

--output:--
[]

和:

1
2
3
4
5
6
if []
  puts %q{It's true!}
end

--output:--
It'
s true.

在ruby中唯一评估为false的值是false本身和nil。空数组,空哈希,空字符串,0等都是正确的。

相反,您可以执行以下操作:

1
2
3
4
5
6
7
8
9
10
if document.xpath("//records//record[@zone_transfer='success']").empty?
  puts"no matching elements"
  #got to next xml file
else
  puts"found matches"
  #do your other xpath search
end

--output:--
no matching elements