2014-02-27 66 views
1

我的XML看起來是這樣的:如何導航XML所有標籤包括屬性

<Servers type="Container"> 
<Server type="Category"> 
    <HostName type="Property">dmitri-spB</HostName> 
    <HostIPAddress type="Property">14.341.516.564</HostIPAddress> 

在這個數據中案件,我不需要的屬性 - 或者至少我只見過在我可能需要的數據中有一個案例。在任何情況下...如果XML是這樣的:

<Servers> 
<Server> 
    <HostName>dmitri-spB</HostName> 
    <HostIPAddress>14.341.516.564</HostIPAddress> 

...我會做這樣的事情:

my $parser = XML::LibXML -> new(); 
    my $tree = $parser -> parse_file ($source_dir."\\".$xmlfiles); 
    for my $Servers ($tree->findnodes ('/Servers')) { 
     foreach my $Server ($Servers->findnodes('./Server')) { 
      $hostname = $Server->findvalue('HostName'); 
      $hostIP = $Server->findvalue('HostIPAddress'); 
     } 
    } 

我試圖在字面上使用整個標籤使用同樣的方法代碼,並得到了「XPath錯誤:無效的表達式」。

因此,確實存在兩個問題 - 當我不關心屬性時如何瀏覽和提取,以及如何在屬性顯着時執行此操作?也許這是一個XPath問題,但我根本無法將XPath文檔與我正在嘗試做的事情聯繫起來。建議?

+0

一個type屬性是什麼XPath表達式給你「的XPath錯誤:無效的表達式」所有Server節點? –

+0

你是否嘗試運行上面顯示的示例代碼?它可能工作得很好。 – mirod

回答

2

您可以完全忽略這些屬性。它們不是您想象的「整個標籤」的一部分,而是每個元素的附加信息。

因此,使用你的代碼,因爲它是,它應該工作。

要按其屬性的值選擇元素,可以在謂詞中使用XPath @表示法。因此,例如,要查找所有Server元素和type屬性Category,您可以編寫Server[type = "Category"]

您可以使用my $document = XML::LibXML->load_data(location => 'myfile')創建解析器對象並一次處理源數據。 location允許您傳遞文件名或URL,還可以指定string並傳遞包含XML或IO的簡單Perl字符串,並傳遞打開的文件句柄以供讀取。

也不需要在單獨的循環中迭代路徑的每一步。例如,您可以加工的Category這樣

use strict; 
use warnings; 

use XML::LibXML; 

my $doc = XML::LibXML->load_xml(location => "$source_dir/$xmlfiles"); 

for my $server ($doc->findnodes('/Servers/Server[@type = "Category"]')) { 
    print ref $server, "\n"; 
} 
+0

是的。如果我在XPath路徑的每個元素中都包含'@'符號,那麼效果很好。沒有它我沒有成功,但沒關係。我已經使用了關於取回所有節點並明確循環它們的提示。由於我的能力有限,顯式循環對我來說更加清晰,但是你的方法迫使我更多地思考實際返回的內容以及我如何訪問內容 - 這對我的大腦來說是一個很好的練習。您已經刪除了我的包版,並且正在按照我的需要運作。 –

+0

上面,我的意思是寫'*而不是*顯式循環',而不是*和*顯式循環。我必須有一些我已經糾正的小錯誤,因爲正如你們所建議的那樣,現在代碼運行得很好,無論是否使用'@'謂詞。一切都很好。 –

+0

@KirkFleming:如你所做的那樣,編寫兩個循環的問題是外層循環只循環一個*'Servers'元素,因此只執行一次。循環的存在不正確意味着有多個節點需要迭代。 – Borodin