2014-10-30 6 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> 

이며, 이것은 내가 XML::LibXML를 사용

<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'속성을 가진 노드"* 무엇을 의미합니까? 'name' 속성이'kalahari' 인'server' 엘리먼트를 옮기고 싶다는 말입니까? – Borodin

+0

시도한 Perl 코드를 보여주십시오. – Borodin

+0

우수. 이것은 완벽 해. 둘 다 감사합니다! 예 Borodin은이 예에서와 같이 name 또는 ip와 같은 일부 속성과 일치합니다. 어디서부터 시작해야할지 모르겠으므로 이동을위한 예제 코드가 없습니다./이걸로 확실히 실행할 수 있습니다. 다시 한 번 감사드립니다! –

답변

2

를 원하는 결과입니다

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

+0

예. 나는 자세를 취한 후에 그것을 알아 차렸지만, 부모로부터 명시 적으로 제거하는 방법을 설명하는 것은 여전히 ​​도움이되었다고 생각했습니다. 명시 적으로 추가 된 덧글 – Miller

+0

질문 : 'my ($ new) = $ xml-> findnodes ('// new');' '을 선언 할 때'my()'의 의미는 무엇입니까? 'my $ new'? –

1

자식 노드와 부모를 모두 찾고 자식을 새 부모로 이동하려면 appendChild으로 호출하면됩니다.

원본 XML 데이터가 config.xml이라는 파일에 있다고 가정하면 코드는 다음과 같습니다.

XML::LibXML에 멋지게 들어간 데이터를 생성하도록 설득하는 더 좋은 방법은 모르겠다. 내가 찾은 가장 좋은 점은 no_blanks을 사용하고 0이 아닌 매개 변수를 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

+0

@nwellnhof : 저것을 보았습니다. 그러나'XML :: LibXML'이 그 자체로 그것을 할 수 없어야하는 이유는 없습니다. 효과적으로 해결할 수있는 다른 모듈이 있다는 점이 마음에 들지 않습니다. 그런데 링크는 ['XML :: LibXML :: PrettyPrint'] (https://metacpan.org/module/XML::LibXML::PrettyPrint)입니다. – Borodin