use strict; use XML::LibXML; my $file = "files/camelids.xml"; my $parser = XML::LibXML->new(); my $tree = $parser->parse_file($file); my $root = $tree->getDocumentElement; my @species = $root->getElementsByTagName("species"); foreach my $camelid (@species) { my $latin_name = $camelid->getAttribute("name"); my @name_node = $camelid->getElementsByTagName("common-name"); my $common_name = $name_node[0]->getFirstChild->getData; my @c_node = $camelid->getElementsByTagName("conservation"); my $status = $c_node[0]->getAttribute("status"); print "$common_name ($latin_name) $status \n"; }XML::LibXML 의 가장 흥미로운 기능 중 하나는 DOM 인터페이스는 물론이고 추가로 XPath 언어를 이용해 노드를 선택할 수 있다는 점이다. 아래의 코드에서는 XPath를 사용하여 원하는 노드를 선택함으로써 앞의 예제와 동일한 결과를 얻을 수 있음을 보여준다.
use strict; use XML::LibXML; my $file = "files/camelids.xml"; my $parser = XML::LibXML->new(); my $tree = $parser->parse_file($file); my $root = $tree->getDocumentElement; foreach my $camelid ($root->findnodes("species")) { my $latin_name = $camelid->findvalue("@name"); my $common_name = $camelid->findvalue("common-name"); my $status = $camelid->findvalue("conservation/@status"); print "$common_name ($latin_name) $status \n"; }위의 코드에서 흥미로운 점은 동일한 노드들의 트리에 DOM 과 XPath 인터페이스의 메소드 중에서 애플리케이션의 필요에 가장 잘 맞는 메소드를 섞어 쓸 수 있다는 것이다.
use strict; use XML::LibXML; my $doc = XML::LibXML::Document->new(); my $root = $doc->createElement("html"); $doc->setDocumentElement($root); my $body = $doc->createElement("body"); $root->appendChild($body); foreach my $item (keys (%camelid_links)) { my $link = $doc->createElement("a"); $link->setAttribute("href", $camelid_links{$item}->{url}); my $text = XML::LibXML::Text->new($camelid_links{$item}->{description}); $link->appendChild($text); $body->appendChild($link); } print $doc->toString;XML::LibXML과 XML::DOM을 구분하는 중요한 차이점은 libxml2의 객체 모델이 W3C DOM 레벨 2 인터페이스에 맞기 때문에 이것이 XML 네임스페이스를 가지고 있는 문서를 더 잘 다룰 수 있다는 점이다. 따라서 XML::DOM은 아래같이 제한적이다.
@nodeset = getElementsByTagName($element_name);그리고
$node = $doc->createElement($element_name);XML::LibXML 은 아래와 같이 할 수도 있다.
@nodeset = getElementsByTagNameNS($namespace_uri, $element_name);그리고
$node = $doc->createElementNS($namespace_uri, $element_name);SAX가 제공하는 즐거움
use XML::LibXML; use XML::LibXML::SAX::Builder; my $builder = XML::LibXML::SAX::Builder->new(); my $driver = CamelDriver->new(Handler => $builder); my $doc = $driver->parse(%camelid_links); # doc is an XML::LibXML::Document object print $doc->toString; package CamelDriver; use base qw(XML::SAX::Base); sub parse { my $self = shift; my %links = @_; $self->SUPER::start_document; $self->SUPER::start_element({Name => "html"}); $self->SUPER::start_element({Name => "body"}); foreach my $item (keys (%camelid_links)) { $self->SUPER::start_element({Name => "a", Attributes => { "href" => $links{$item}->{url} } }); $self->SUPER::characters({Data => $links{$item}->{description}}); $self->SUPER::end_element({Name => "a"}); } $self->SUPER::end_element({Name => "body"}); $self->SUPER::end_element({Name => "html"}); $self->SUPER::end_document; } 1;XML::LibXML::SAX::Generator를 이용해 기존의 DOM 트리에서 SAX 이벤트를 발생시킬 수도 있다. 아래의 코드에서 camelids.xml 파일을 파싱하여 만들어진 DOM 트리가 XML::LibXML::SAX::Generator의 generate() 메소드에 넘겨지면 XML::Handler::XMLWriter 에 있는 이벤트 핸들러가 호출되어 문서를 STDOUT으로 출력하게 된다.
use strict; use XML::LibXML; use XML::LibXML::SAX::Generator; use XML::Handler::XMLWriter; my $file = "files/camelids.xml"; my $parser = XML::LibXML->new(); my $doc = $parser->parse_file($file); my $handler = XML::Handler::XMLWriter->new(); my $driver = XML::LibXML::SAX::Generator->new(Handler => $handler); # generate SAX events that are captured # by a SAX Handler or Filter. $driver->generate($doc);SAX 이벤트를 받아들이고 내보낼 수 있는 기능은 최근 이 컬럼에서 논의되었던 비XML 자료에서 SAX 이벤트를 발생시키고 SAX 필터 체인을 작성하는 것과 연관지어 생각해보면 아주 유용하다고 볼 수 있다. 예를 들면 펄로 쓰여진 SAX 드라이버를 이용해 데이터베이스 질의에서 가져온 자료에 기반을 두고 이벤트를 발생시켜 DOM 객체를 만들 수 있다. 이 DOM 객체는 C-space에서 디스플레이를 위해 XSLT와 굉장히 빠른 libxslt 라이브러리 (이것은 libxml2 DOM 객체를 기대한다)를 사용해 변환되고, 변환된 DOM 트리에서 커스텀 SAX 필터를 이용한 추가 처리를 위해 SAX 이벤트를 발생시켜 최종 마무리를 한다. 즉 이 모든 것을 하면서 스트링을 다시 파싱하기 위해 문서를 직렬화할 필요가 한 번도 없다는 이야기다. 정말 놀랍지 않은가!
이전 글 : C++ 언어의 시시한 역사
다음 글 : 파이썬 1.6b1 라이센스의 숨겨진 뒷 이야기
최신 콘텐츠