【问题标题】:xpath expression in findnodes() returning empty nodelistfindnodes() 中的 xpath 表达式返回空节点列表
【发布时间】:2012-06-04 23:14:11
【问题描述】:

XML:

<zoo xmlns="http://www.zoo.com" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:schemaLocation="http://www.zoo.com employee.xsd">

<area id="1" posizione="nord" nome="scimmie">
    <animale>
        <nome>Gigi</nome>
        <sesso>Male</sesso>
        <eta>3</eta>
    </animale>

    <animale>
        <nome>Gigia</nome>
        <sesso>Female</sesso>
        <eta>2</eta>
    </animale>
</area>

<area id="2" posizione="nord" nome="giraffe">
    <animale>
        <nome>Giro</nome>
        <sesso>Male</sesso>
        <eta>6</eta>
    </animale>

    <animale>
        <nome>Gira</nome>
        <sesso>Female</sesso>
        <eta>5</eta>
    </animale>
</area>
</zoo>

代码:

my $parser = XML::LibXML->new;
my $doc = $parser->parse_file("../xml/animals.xml");
my $root = $doc->getDocumentElement();

my $new_animal = $doc->createElement("animale");

my $name_element = $doc->createElement("nome");
$name_element->appendTextNode($name);

my $gender_element = $doc->createElement("sesso");
$gender_element->appendTextNode($gender);

my $age_element = $doc->createElement("eta");
$age_element->appendTextNode($age);

$new_animal->appendChild($name_element);
$new_animal->appendChild($gender_element);
$new_animal->appendChild($age_element);

my $area_element = $root -> findnodes("//area[\@id=$area]")->get_node(1);

$area_element->appendChild($new_animal);

$area 是一个区域的 id(现在我正在测试通常是 1)

我的目的是创造一种新动物并将其添加到适当的区域

但我的问题是指令

    my $area_element = $root -> findnodes("//area[\@id=$area]")->get_node(1);

不起作用,因为 $area_element 是 undef,因为 findnodes 总是返回一个空节点列表(检查打印 size())。

我认为问题出在 findnodes 中的 xpath 表达式,但我不明白出了什么问题,我在另一个库 (XML::XPath) 中使用了相同的表达式并且它正在工作。

怎么了?

【问题讨论】:

    标签: xml perl xpath xlib


    【解决方案1】:

    您的 XML 中默认命名空间的 URI 是 http://www.zoo.com,因此您必须在 XPath 表达式中指定它以获取节点。

    这样做的方法是声明一个XML::LibXML::XPathContext 对象,为这个命名空间分配一个名称。然后可以在 XPath 表达式中使用该名称来访问节点。

    如果你写

    my $xpc = XML::LibXML::XPathContext->new;
    $xpc->registerNs('zoo', 'http://www.zoo.com');
    

    您现在有一个上下文,其中 XML 的默认命名空间名为 zoo。现在你可以写了

    my $area_element = $xpc->findnodes("//zoo:area[\@id=$area]", $doc)->get_node(1);
    

    你会找到正确的&lt;area&gt;元素。

    【讨论】:

    • 我尝试了你的代码,但我得到了这个: ---------- 软件错误:XPathContext:在 /Users/toyo/Sites/zoo/cgi-bin 丢失当前节点/_nuovo_animale.cgi 第 76 行 --------- 第 76 行是:my $area_element = $xpc -> findnodes("//zoo:area[\@id=$area]")->get_node(1 );
    • @qwertoyo,这是一个新问题,这里实在没地方讨论了。请提出一个新问题,并提供演示该问题所需的最少可运行代码。
    • @qwertoyo,试试更简单的:my ($area_element) = $xpc-&gt;findnodes("//zoo:area[\@id=$area]", $doc);
    • 看到你对答案的编辑(添加了“,$doc”),现在它似乎工作了,我正在测试它
    【解决方案2】:

    命名空间声明错误,应该是&lt;zoo xmlns:zoo="http://www.zoo.com"之类的。

    【讨论】:

    • xmlns="http://www.zoo.com" 没有命名空间 ID 只会绑定 default 命名空间,即所有不带前缀的元素的命名空间。如果没有定义默认命名空间,那么就好像使用了声明 xmlns=""
    • &lt;foo xmlns="..."&gt;&lt;bar:foo xmlns:bar="..."&gt; 是正确且等价的(假设孩子模仿前缀的缺失/存在)。 &lt;foo xmlns:bar="..."&gt; 中定义的命名空间从未使用过,因此您的建议不正确。
    • 错误答案。命名空间声明没有任何问题。投反对票。
    猜你喜欢
    • 1970-01-01
    • 2017-10-27
    • 1970-01-01
    • 2017-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-20
    • 1970-01-01
    相关资源
    最近更新 更多