我使用的是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.xss的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'
这是Perl绑定的一个限制。XML::LibXML
总是在上下文节点的作用域中注册所有名称空间。您所能做的就是将现有前缀重新绑定到另一个命名空间,就像您在问题的编辑部分所做的那样。如果您删除对unregisterNS
的调用,它应该执行您想要的操作:
$xpc2->registerNs('bar', 'nothing'); # Rebind prefix
my @nodes = $xpc2->findnodes('bar:id', $par);
print scalar(@nodes), "n"; # Prints 0
是因为bar
命名空间尚未注册吗?如果我在unregisterNs
调用之前添加$xpc2->registerNs('bar', 'www.bar.com');
,程序对我来说运行得很好。这会产生你想要的行为吗?
根据附加信息更新:进行查询的方式可能会暴露出libxml或XML::libxml中的错误;我对XPathContext不够熟悉,不知道它是否是一个bug。所以我尝试了一些让我困惑的东西,在我做了unregisterNS
之后,我做了一个lookupNS
,我仍然得到了正确的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
命令。