Re: XML::LibXML::XPathContext namespace confusion

Grant McLean <[email protected]>
Newsgroups gmane.comp.lang.perl.xml
Message-ID <[email protected]>
On Wed, 2009-09-09 at 18:09 -0400, Scott Stansbury wrote:
> I am confused with the namespace issues using XML::LibXML::XPathContext.

It *is* confusing.  The key point is that the only thing that really
matters is the namespace URI.  The prefix used in the document is not
relevant.  Whether you choose to associate the URI with the same prefix
as was used in the document is your choice - XML::LibXML doesn't care
either way.


> my $xp = XML::LibXML::XPathContext->new($data_file);

Rather than passing the constructor a filename, you'll want to pass it a
document element - which means you'll have to parse the document first,
e.g.:

my $parser = XML::LibXML->new();
my $doc    = $parser->parse_file($data_file);
my $xc     = XML::LibXML::XPathContext->new( $doc->documentElement() );

Now you need to register a namespace prefix for each namespace that you
want to use in a query, e.g.:

$xc->registerNs( def  => 'http://scap.nist.gov/schema/feed/vulnerability/2.0' );
$xc->registerNs( vuln => 'http://scap.nist.gov/schema/vulnerability/0.4' );
$xc->registerNs( cvss => 'http://scap.nist.gov/schema/cvss-v2/0.2' );

Your example document included a default namespace declaration so every
element in the document without a namespace prefix is associated with
the default namespace URI (well that's an oversimplification but it will
do for now).

Now you'll use the XPathContext object to do the XPath searches:

for my $entry ($xc->findnodes("/def:nvd/def:entry[\@id = '$cve_id']")) {

Note I used the def: prefix to specify that I wanted to match elements
in the document default namespace.

The nodes that are returned are (confusingly) plain LibXML DOM nodes and
have no knowledge of namespaces so if you want to do a relative search
then you need to use the $xc object again and give it a context node:

my ($metrics) = $xc->findnodes('vuln:cvss/cvss:base_metrics', $entry)
  or die "Failed to find metrics for entry $cve_id";

my $av = $xc->find('cvss:access-vector', $metrics);

That should be enough to get you going.

Cheers
Grant


_______________________________________________
Perl-XML mailing list
[email protected]
To unsubscribe: http://listserv.ActiveState.com/mailman/mysubs
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.