3

我正在使用 XML::LibXML。在创建 XPath 上下文时,我需要能够准确指定哪些名称空间可用。但是,上下文节点范围内的所有名称空间都会自动注册到 XPathContext 对象中。我需要注销它们,但是当我尝试注销上下文节点范围内的命名空间时出现错误:

use XML::LibXML;
use XML::LibXML::XPathContext;

my $xml = <<'__EOI__';
<?xml version="1.0"?>
<myDoc id="myDocId">
    <body id="bodyId">
    <baz:par xmlns:baz="www.baz.com"
             xmlns:bar="www.bar.com">
        <bar:id>xyz123</bar:id>
    </baz:par>
    </body>
</myDoc>
__EOI__

my $parser = XML::LibXML->new();
my $doc = $parser->parse_string($xml);

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

my $par = ${ $xpc->findnodes('//baz:par', $doc) }[0];

my $xpc2 = XML::LibXML::XPathContext->new($par);
$xpc2->unregisterNs('bar');

上面的呱呱叫XPathContext: cannot unregister namespace。检查源代码,我看到错误是从LibXML.xs的第 7618 行打印的。它在函数xmlXPathRegisterNs返回 -1 时打印。我能在xmlsoft.org上找到这个函数的唯一文档。该文档指定 -1 返回值表示存在错误,但未指定在什么情况下会发生错误。我终其一生都找不到这种方法的来源。

XPath 规范很可能不允许这种特定操作,但我也无法确定这一点。

谁能告诉我 a) 是否有办法使用 XML::LibXML::XPathContext 取消注册上下文节点范围内的命名空间,或者 b) 有文档表明在 XPath 中不允许这样做?

编辑

Joel 向我展示了如果您没有手动注册命名空间,取消注册命名空间只会引发给定的错误。但是,注销仍然无法正常工作:

$xpc2->registerNs('bar', 'nothing'); #otherwise unregistering throws an error
$xpc2->unregisterNs('bar');
my @nodes = $xpc2->find('bar:id');
print scalar @nodes; #I want '0', but this prints '1'
4

2 回答 2

1

这是 Perl 绑定的限制。XML::LibXML总是在上下文节点范围内注册所有命名空间。您所能做的就是将现有前缀重新绑定到另一个命名空间,就像您在问题的编辑部分所做的那样。如果您删除对 的调用unregisterNS,它应该做您想做的事情:

$xpc2->registerNs('bar', 'nothing'); # Rebind prefix
my @nodes = $xpc2->findnodes('bar:id', $par);
print scalar(@nodes), "\n"; # Prints 0
于 2013-09-22T13:30:29.470 回答
0

是因为bar命名空间还没有注册吗?如果我$xpc2->registerNs('bar', 'www.bar.com');在通话之前添加unregisterNs,程序对我来说运行良好。这会产生你想要的行为吗?

从附加信息更新: 您进行查询的方式可能揭示了 libxml 或 XML::LibXML 中的错误;我对 XPathContext 不够熟悉,无法知道它是否是错误。所以我尝试了一些让我感到困惑的事情,我做了一个lookupNS之后unregisterNS我仍然得到了正确的 NS:

$xpc2->registerNs('bar', 'www.bar.com');
$xpc2->unregisterNs('bar');
print $xpc2->lookupNs('bar') . "\n"; # print www.bar.com

但是,我可能有一个解决方案可以满足您的需求。而不是使用'bar'作为我尝试使用的前缀'bob',我认为它可能会给你你正在寻找的行为:

$xpc2->registerNs('bob', 'www.bar.com');
$xpc2->unregisterNs('bob');
my @nodes = $xpc2->find('bob:id');
print scalar @nodes . "\n";

这样做会导致该find方法引发异常。代码不会到达print scalar命令。

于 2013-07-16T22:05:22.227 回答