2013-06-16 2 views
1

나는 XML Simple을 시도했지만 XML을 해시로 읽으므로 DTD에 대해 실행하면 출력물은 쓸모가 없습니다. 어려운 길을 배웠다.XML :: LibXML을 사용하여 CableLabs 1.0 XML 파일의 특정 부분을 찾아서 바꿉니다.

그래서 XML::LibXML을 채택했습니다. 재미있는 점은 XML::Simple으로 수행하기가 가장 어려웠던 요구 사항이 가장 쉽다는 것입니다. 그러나 나는 XML::Simple에서 더 쉽게 할 수있는 것들 중 일부는 불가능하다는 것을 증명하고있다. DOM에 대한 나의 이해 부족과 XML::LibXML과 같은 혼란스러운 행동들로 인해.

<Metadata> 
     <ADI Name="movie" /> 
     <App_Data Name="Something I don't care about" value="who cares" /> 
     <App_Data Name="Something I don't care about as well" value="who cares" /> 
     <App_Data Name="ChangeMe" Value="" /> 
    </Metadata> 
    <Metadata> 
     <ADI Name="photo" /> 
     <App_Data Name="Something I don't care about" value="who cares" /> 
     <App_Data Name="Something I don't care about as well" value="who cares" /> 
     <App_Data Name="ChangeMe" Value="" /> 
    </Metadata> 
    <Metadata> 
     <ADI Name="poster" /> 
     <App_Data Name="Something I don't care about" value="who cares" /> 
     <App_Data Name="Something I don't care about as well" value="who cares" /> 
     <App_Data Name="ChangeMe" Value="" /> 
    </Metadata> 

참고 :

그래서 여기에 XML의 샘플입니다 나는이 게시물에 사용이 단순화했다.

그래서 기본적으로 나는 NameChangeMe이다 년대 <App_Data> 태그의 Value 특성에 변화를 만들기 위해 내가 DOM의 올바른 영역에 있음을 확인하기 위해 <ADI> 태그에 Name 필드를 사용합니다.

이것은 내가 생각해 낸 코드 스 니펫입니다 ... 그리고 비참하게 실패했습니다.

#!/usr/bin/perl 

use strict; 
use XML::LibXML; 

my $xml2 = XML::LibXML->new(); 
my $data = $xml2->parse_file("adi.xml"); 
my $movie; 
my $photo; 
my $poster; 

foreach my $test ($data->findnodes('//Metadata')) { 
    if ($test->findvalues('./ADI/@Name[.="movie"]')){ 
     $movie = 1; 
     undef $photo; 
     undef $poster; 
    } 
    elsif ($test->findvalues('./ADI/@Name[.="photo"]')){ 
     undef $movie; 
     $photo = 1; 
     undef $poster; 
    } 
    elsif ($test->findvalues('./ADI/@Name[.="poster"]')){ 
     undef $movie; 
     undef $photo; 
     $poster = 1; 
    } 
} 

작동하지 않기 때문에이 외에 아무것도 없습니다. 나는이 질문에 대한 보너스로

Can't locate object method "findvalues" via package "XML::LibXML::Element" 

의 라인을 따라 오류 무언가를 얻을 내가 완전히 사진 및/또는 포스터에 포함 된 것들에 대한 <Metadata> (모든 어린이)를 제거하기를 원한다면 무엇?

+0

'미확정의 $ var에가,'펄이 추가 작업을 수행하는 원인이,''$ var에 = 미확정의 특별 버전입니다. 후자를 사용하십시오. – ikegami

+0

일단''로 무엇을 하려는지 명확하지 않으면'Metadata' 타입을 확인하십시오. 변화 후 어떻게 생겼을까요? – doubleDown

답변

3

처음 사용해보십시오.

#!/usr/bin/perl 

use strict; 
use XML::LibXML; 

my $xml2 = XML::LibXML->new(); 
my $data = $xml2->parse_file("adi.xml"); 

foreach my $test ($data->findnodes('//Metadata')) { 
    if ($test->findnodes('./ADI/@Name[.="movie"]')){ 
     print "movie\n"; 
    } 
    elsif ($test->findnodes('./ADI/@Name[.="photo"]')){ 
     print "photo\n"; 
    } 
    elsif ($test->findnodes('./ADI/@Name[.="poster"]')){ 
     print "poster\n"; 
    } 
} 

findvalues 방법이 없습니다. 당신이하고자하는 것은 findnodes을 사용하는 것인데, XPath 표현식과 일치하는 노드의 목록을 돌려 줄 것입니다. 이미 가지고있는 경우 목록에서 반복하여 필요한 데이터를 추출 할 수 있습니다. 이는 이미 Metadata에서하는 것과 같습니다.

또한 XML 파일에 단일 루트 수준 요소가 있다고 가정합니다. 아래의 수정 된 버전을 사용하여 위의 코드를 테스트했습니다.

<root> 
    <Metadata> 
     <ADI Name="movie" /> 
     <App_Data Name="Something I don't care about" value="who cares" /> 
     <App_Data Name="Something I don't care about as well" value="who cares" /> 
     <App_Data Name="ChangeMe" Value="" /> 
    </Metadata> 
    <Metadata> 
     <ADI Name="photo" /> 
     <App_Data Name="Something I don't care about" value="who cares" /> 
     <App_Data Name="Something I don't care about as well" value="who cares" /> 
     <App_Data Name="ChangeMe" Value="" /> 
    </Metadata> 
    <Metadata> 
     <ADI Name="poster" /> 
     <App_Data Name="Something I don't care about" value="who cares" /> 
     <App_Data Name="Something I don't care about as well" value="who cares" /> 
     <App_Data Name="ChangeMe" Value="" /> 
    </Metadata> 
</root> 

나는 Perl의 LibXML 라이브러리에 유용한 this cheatsheet을 찾았습니다.

2
  • findvalues은 어디에서 찾을 수 있습니까? 문서 도구 : .

    @nodes = $node->findnodes($xpath_expression); 
    $result = $node->find($xpath); 
    print $node->findvalue($xpath); 
    
  • 왜 그렇게 많은 용도?

    ./ADI/@Name[.="movie"] 
    

    아마 당신은 하나 개 이상의 메타 데이터 요소를 가지고 있지만, 당신은 혼자가 마지막에 따라 변수를 설정

    ADI[@Name="movie"] 
    
  • 해야한다.

  • 한 가지 정보를 저장하는 데 세 가지 변수를 사용하면 안됩니다.

#!/usr/bin/perl 

use strict; 
use warnings; 

use XML::LibXML qw(); 

my $parser = XML::LibXML->new(); 
my $doc = $parser->parse_file("adi.xml"); 

for my $metadata ($doc->findnodes('//Metadata')) { 
    my ($adi_type) = $metadata->find('ADI/@Name') 
     or next; 

    my ($app_data) = $metadata->find('App_Data[@Name="ChangeMe"]'); 

    if ($adi_type eq 'movie') { 
     ... 
    } 
    elsif ($adi_type eq 'photo') { 
     ... 
    } 
    elsif ($adi_type eq 'poster') { 
     ... 
    } 
} 


또는 당신도 사용할 수 있습니다.

my ($movie_adi) = $doc->findnodes('//Metadata[ADI/@Name="movie"]'); 
my ($movie_app_data) = $movie_adi->findnodes('App_Data[@Name="ChangeMe"]'); 
... 

my ($photo_adi) = $doc->findnodes('//Metadata[ADI/@Name="photo"]'); 
my ($photo_app_data) = $photo_adi->findnodes('App_Data[@Name="ChangeMe"]'); 
... 

my ($poster_adi) = $doc->findnodes('//Metadata[ADI/@Name="poster"]'); 
my ($poster_app_data) = $poster_adi->findnodes('App_Data[@Name="ChangeMe"]'); 
... 
2

많은이 관심있는 노드를 찾기 위해 XPath 식으로 수행 할 수 있습니다

이 프로그램은 귀하가 요청한 것을 처리합니다. 잘 구성된 XML 문서로 만들기 위해 데이터에 루트 요소 <root>을 추가했습니다.

use strict; 
use warnings; 

use XML::LibXML; 

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

for my $metadata ($doc->findnodes('//Metadata')) { 
    if ($metadata->findnodes('ADI[@Name = "movie" or @Name = "photo"]')) { 
    $metadata->parentNode->removeChild($metadata); 
    } 
} 

print $doc->toString(1); 

출력

<?xml version="1.0"?> 
<root> 
    <Metadata> 
    <ADI Name="poster"/> 
    <App_Data Name="Something I don't care about" value="who cares"/> 
    <App_Data Name="Something I don't care about as well" value="who cares"/> 
    <App_Data Name="ChangeMe" Value=""/> 
    </Metadata> 
</root> 
+0

좋은 친구. Mayhap'$ metadata-> unbindNode();'는 노드를 분리하는 좀 더 간결한 방법입니까? – doubleDown