LibXML findnodes($query)

风格不统一 提交于 2019-12-25 04:05:31

问题


I'm having some trouble with this code:

my $file= '../xml/news.xml';
my $parser= XML::LibXML->new();
my $doc = $parser->parse_file($file);
my $xpc = XML::LibXML::XPathContext->new($doc);
my $query = '/notizie/news[@id='.$newsId.']';
print $query;
my $node = $xpc->findnodes($query)->get_node(1);

print $node;

In particular "print $node" prints an empty string, even if the XML file path is correct and the XPath query should return a node.

The "funny" thing is that if i use:

my $query = '/*/*[@id='.$newsId.']'; 

i got the right result.

This is the news.xml file:

<?xml version="1.0"?>
<notizie xmlns="http://www.9armonie.com/news"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://www.9armonie.com/news news.xsd">
    <news id="3">
        <data>2015-01-01</data>
        <ora>12:00:00</ora>
        <titolo>Title 3</titolo>
        <descrizione> Description 3</descrizione>
    </news>     
    <news id="2">
        <data>2014-12-19</data>
        <ora>12:00:00</ora>
        <titolo>Title 2</titolo>
        <descrizione> Description 2</descrizione>
    </news>
    <news id="1">
        <data>2014-12-18</data>
        <ora>12:00:00</ora>
        <titolo>News 1</titolo>
        <descrizione> Desc 1</descrizione>
    </news>
    <news id="0">
        <data>2014-12-18</data>
        <ora>12:00:00</ora>
        <titolo> asdasd</titolo>
        <descrizione> First! </descrizione>
    </news>
</notizie>

回答1:


Your input XML document is in a default namespace:

<notizie xmlns="http://www.9armonie.com/news"/>

This element and all its descendants are in that namespace, and an expression like //notizie will never be successful because it looks for an element without a namespace.

On the other hand, that's also why /*/* returns the elements - because * matches elements in any (or no) namespace. There is nothing funny about it really.

Either declare this namespace in your Perl code (the better option), or ignore namespaces in your XPath expression.

Declaring the namespace with LibXML

I believe declaring namespaces in LibXML is done with registerNs(), see the relevant CPAN page. Declare the namespace URI from the input XML together with a prefix (news:, in this example) that you can then use to qualify the element names in the XPath expression.

my $xpc = XML::LibXML::XPathContext->new($doc);
$xpc->registerNs('news', 'http://www.9armonie.com/news');
my $query = '/news:notizie/news:news[@id='.$newsId.']';
my $node = $xpc->findnodes($query)->get_node(1);

Ignoring namespaces

The second option means modifying your XPath expression to

"/*[local-name() = 'notizie']/*[local-name() = 'news' and @id='.$newsId.']"

The above expression will find the notizie element in all of the following documents:

<!--No namespace-->
<notizie/>

<!--Namespace with prefix-->
<news:notizie xmlns:news="http://www.9armonie.com/news"/>


<!--Default namespace-->
<notizie xmlns="http://www.9armonie.com/news"/>


来源:https://stackoverflow.com/questions/28203151/libxml-findnodesquery

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!