2012-10-18 22 views
1

我正在嘗試編寫一個ruby腳本來取出Nexpose Simple XML結果導出,解析它,並將所需結果寫入一個更漂亮的格式以便於查看。我正在使用Nokogiri來解析XML。我的問題是我有一個嵌套的循環,對於每個設備,遍歷每個服務部分並從每個設備中取出名稱,端口和協議屬性。這最終將被打印迴文件文件或csv文件。但是,我的嵌套循環似乎只從第一個服務部分拉出這三個屬性並重復打印它們。Nexpose XML結果解析器中的Ruby/Nokogiri嵌套循環失敗

採樣輸入(會有這些設備塊的多於一個):

<device address="10.x.x.1" id="20xx"> 
<fingerprint certainty="0.85"> 
<description>Microsoft Windows</description> 
<vendor>Microsoft</vendor> 
<family>Windows</family> 
<product>Windows</product> 
<version/> 
<device-class>General</device-class> 
<architecture/> 
</fingerprint> 
<vulnerabilities> 
</vulnerabilities> 
<services> 
<service name="NTP" port="123" protocol="udp"> 
<vulnerabilities> 
</vulnerabilities> 
</service> 
<service name="HTTP" port="8080" protocol="tcp"> 
<fingerprint certainty="0.75"> 
<description>Apache</description> 
</device> 

<device address="10.x.x.2" id="20xx"> 
<fingerprint certainty="0.85"> 
<description>Microsoft Windows</description> 
<vendor>Microsoft</vendor> 
<family>Windows</family> 
<product>Windows</product> 
<version/> 
<device-class>General</device-class> 
<architecture/> 
</fingerprint> 
<vulnerabilities> 
</vulnerabilities> 
<services> 
<service name="DNS" port="53" protocol="udp"> 
<vulnerabilities> 
</vulnerabilities> 
</service> 
<service name="HTTP" port="80" protocol="tcp"> 
<fingerprint certainty="0.75"> 
<description>Apache</description> 
</device> 

紅寶石代碼:

#! /usr/bin/env ruby 

require 'rubygems' 
require 'nokogiri' 

doc = Nokogiri::XML(open('report.xml').read) 
device = doc.xpath('//device') 

device.each do |d| 
service = d.xpath('//service') 
puts d.attr('address') 

service.each do |s| 
    name = s.attr('name') 
    port = s.attr('port') 
    protocol = s.attr('protocol') 

    puts port 
    puts protocol 
    puts name 
end 
end 

所需的輸出:

10.x.x.1 
123 
udp 
NTP 
8080 
tcp 
HTTP 

10.x.x.2 
53 
udp 
DNS 
80 
tcp 
HTTP 

實際輸出:

123 
NTP 
udp 
123 
NTP 
udp 

因此,代碼應該顯示服務端口,名稱和協議的列表爲每個設備的每個服務。但是,當前的代碼似乎只是一遍又一遍地打印第一個服務(即123,NTP和udp)的集合。

我錯過了我的循環邏輯中的東西?或者你看到循環有什麼問題?任何幫助獲得這項工作將有所幫助。謝謝。

回答

0

請注意,XPath構造//意味着在文檔中找到元素的任何地方。您不想在內部循環中執行此操作,因爲您已經爲您的設備完成了該操作。

更新

基於新的輸入文檔,這裏是提取你需要的信息的一種方式。我冒昧地使用CSV,爲一個很好的Excel輸出文件。請注意,有一個單個解析循環。代碼:

require 'nokogiri' 
require 'csv' 

doc = Nokogiri::XML(open('report.xml').read) 

CSV.open("devices.csv", "wb") do |csv| 
    csv << ["Device", "Service", "Port", "Protocol"] 
    doc.search('//service').each do |s| 
    device = s.xpath('ancestor::device[1]/@address') 
    name = s.attr('name') 
    port = s.attr('port') 
    protocol = s.attr('protocol') 
    csv << [device, name, port, protocol] 
    end 
end 

這裏是devices.csv內容:

Device,Service,Port,Protocol 
10.x.x.1,NTP,123,udp 
10.x.x.1,HTTP,8080,tcp 
10.x.x.2,DNS,53,udp 
10.x.x.2,HTTP,80,tcp 
+0

我做你的建議的修改,並在設備環路中加入一行把設備地址。所以輸出結果應該是IP地址,然後是所有端口的醜陋列表,然後是下一個IP等等。那麼,它至少會提供額外服務的信息。然而,它看起來是打印第一個IP地址,然後是所有設備的所有服務,然後是第二個IP地址,然後是所有設備的所有服務,然後沖洗並重復。不應該將服務循環限制在單個設備部分,因爲它們是在設備循環中迭代的? – vidkun

+0

在你的示例代碼中,你似乎沒有使用任何設備。你可以刪除它。我已經更新了我的答案。 –

+0

它應該用於遍歷輸入xml文件中的多個設備節。因此,爲多個不同的主機重複多次重複提供上面提供的示例輸入。所以我的循環(至少我希望)應該遍歷每個設備部分,併爲該部分提供所有服務,然後轉到下一個設備。相反,我目前正在輸出設備A的地址,然後輸出每個設備的服務列表,設備B的地址,以及每個設備的服務列表,一直排在列表的後面。 – vidkun