2014-10-30 78 views
1

我已經嘗試了幾種不同的解析XML文檔的方法。我需要在文檔中找到具有x屬性的節點,然後將該節點及其子節點移動到不同的父節點。如何使用Perl移動XML數據中的節點

我已經有一些成功的使用XML::LibXML定位節點,並能夠遍歷它的孩子,但我堅持如何將其移動到不同的父。

使用$node->cloneNode(1)看起來很有希望,但我找不到它的使用的好例子。

這是原始的XML數據

<config logdir="/var/log/foo/" debugfile="/tmp/foo.debug"> 
    <old> 
    <server name="sahara" osname="solaris" osversion="2.6"> 
     <address ip="10.0.0.101">Private</address> 
     <address ip="10.0.1.101">Private</address> 
    </server> 
    <server name="gobi" osname="irix" osversion="6.5"> 
     <address ip="10.0.0.102">Private</address> 
    </server> 
    <server name="kalahari" osname="linux" osversion="2.0.34"> 
     <address ip="10.0.0.103">Private</address> 
     <address ip="10.0.1.103">Private</address> 
    </server> 
    </old> 
    <new> 
    </new>   
</config> 

,這是結果,我想

<config logdir="/var/log/foo/" debugfile="/tmp/foo.debug"> 
    <old> 
    <server name="sahara" osname="solaris" osversion="2.6"> 
     <address ip="10.0.0.101">Private</address> 
     <address ip="10.0.1.101">Private</address> 
    </server> 
    <server name="gobi" osname="irix" osversion="6.5"> 
     <address ip="10.0.0.102">Private</address> 
    </server> 
    </old> 
    <new> 
    <server name="kalahari" osname="linux" osversion="2.0.34"> 
     <address ip="10.0.0.103">Private</address> 
     <address ip="10.0.1.103">Private</address> 
    </server> 
    </new>   
</config> 
+0

你說的*。* 「與 'X' 屬性的節點」 是什麼意思?你是說你想移動'''屬性'kalahari'的'server'元素嗎? – Borodin 2014-10-30 20:40:27

+0

請顯示您試過的Perl代碼 – Borodin 2014-10-30 20:41:30

+0

非常好。太棒了。謝謝你們倆!是的,鮑羅廷,如在這個例子中,匹配一些屬性,如名稱或IP。我沒有移動示例代碼,因爲我不知道從哪裏開始:/我肯定可以用這個來運行。再次感謝! – 2014-10-31 10:57:07

回答

2

使用XML::LibXML

use strict; 
use warnings; 

use XML::LibXML; 

my $xml = XML::LibXML->load_xml(IO => \*DATA); 

my ($new) = $xml->findnodes('//new'); 

for my $linux ($xml->findnodes('//old/server[@osname="linux"]')) { 
    $linux->unbindNode();   # Remove from Parent (done automatically when added elsewhere without cloning) 
    $new->addChild($linux); 
} 

print $xml; 

__DATA__ 
<config logdir="/var/log/foo/" debugfile="/tmp/foo.debug"> 
    <old> 
     <server name="sahara" osname="solaris" osversion="2.6"> 
      <address ip="10.0.0.101">Private</address> 
      <address ip="10.0.1.101">Private</address> 
     </server> 
     <server name="gobi" osname="irix" osversion="6.5"> 
      <address ip="10.0.0.102">Private</address> 
     </server> 
     <server name="kalahari" osname="linux" osversion="2.0.34"> 
      <address ip="10.0.0.103">Private</address> 
      <address ip="10.0.1.103">Private</address> 
     </server> 
    </old> 
    <new> 
    </new>  
</config> 

輸出:

<?xml version="1.0"?> 
<config logdir="/var/log/foo/" debugfile="/tmp/foo.debug"> 
    <old> 
     <server name="sahara" osname="solaris" osversion="2.6"> 
      <address ip="10.0.0.101">Private</address> 
      <address ip="10.0.1.101">Private</address> 
     </server> 
     <server name="gobi" osname="irix" osversion="6.5"> 
      <address ip="10.0.0.102">Private</address> 
     </server> 

    </old> 
    <new> 
    <server name="kalahari" osname="linux" osversion="2.0.34"> 
      <address ip="10.0.0.103">Private</address> 
      <address ip="10.0.1.103">Private</address> 
     </server></new>  
</config> 
+0

沒有必要'unbindNode' – Borodin 2014-10-30 21:01:30

+0

是的。我注意到,在定位後,但認爲它仍然有助於演示如何明確地從父項中移除。添加評論爲明確 – Miller 2014-10-30 22:03:43

+0

問題: 聲明:my()'時,我的($ new)= $ xml-> findnodes('// new');' 的意義是什麼,而不僅僅是'我的$新'? – 2014-11-04 15:30:53

1

您只需找到子節點和父節點,然後通過調用appendChild將子節點移動到新父節點。

假設您的原始XML數據位於名爲​​3210的文件中,代碼將如下所示。

我不知道一個更好的方式來說服XML::LibXML產生很好的縮進數據。我發現的最好的方法是啓用no_blanks,並使用非零參數toString,但正如您所看到的,這與理想情況相差甚遠。

use strict; 
use warnings; 

use XML::LibXML; 

my $xml = XML::LibXML->load_xml(location => 'config.xml', no_blanks => 1); 

my ($kalahari) = $xml->findnodes('/config/old/server[@name="kalahari"]'); 

my ($new) = $xml->findnodes('/config/new'); 

$new->appendChild($kalahari); 

print $xml->toString(1); 

輸出

<?xml version="1.0"?> 
<config logdir="/var/log/foo/" debugfile="/tmp/foo.debug"> 
    <old> 
    <server name="sahara" osname="solaris" osversion="2.6"> 
     <address ip="10.0.0.101">Private</address> 
     <address ip="10.0.1.101">Private</address> 
    </server> 
    <server name="gobi" osname="irix" osversion="6.5"> 
     <address ip="10.0.0.102">Private</address> 
    </server> 
    </old> 
    <new> 
    <server name="kalahari" osname="linux" osversion="2.0.34"><address ip="10.0.0.103">Private</address><address ip="10.0.1.103">Private</address></server></new> 
</config> 
+1

'no_blanks'主要是黑客。要獲得格式良好的輸出,「XML :: LibXML :: PrettyPrint」可能是最佳選擇。 – nwellnhof 2014-10-30 23:00:35

+0

@nwellnhof:我看了一下,但沒有看到爲什麼'XML :: LibXML'本身無法做到這一點。我不喜歡有一個完整的其他模塊是有效的解決方法。順便說一句,鏈接是['XML :: LibXML :: PrettyPrint'](https://metacpan.org/module/XML::LibXML::PrettyPrint) – Borodin 2014-10-31 01:02:59

相關問題