如何使Perl XML :: XPath允许没有名称空间前缀的查询?

时间:2013-05-21 18:23:37

标签: xml perl xpath

我正在尝试使用XML :: XPath从XML文档中提取内容。文档是使用命名空间指定的,但我想使用没有命名空间的XPath表达式。据我所知,我在两个不同的脚本中完成了这项工作。

在今天的某个时候,XML :: XPath的行为已经发生了变化。我没有看到我的改变使得这种行为发生了变化。

如果我几乎完全指定名称空间,在脚本中调用“set_namespace()”(硬编码我希望使用的前缀)并在XPath表达式中指定前缀,我可以使用一些手动测试。 / p>

同样,我很确定我昨天有这个工作,没有在脚本中调用“set_namespace()”,或者在XPath表达式中指定前缀。

如果我没有添加“set_namespace()”调用并在表达式中指定前缀,我只是从查询中获取空节点集。

我在创建第一个XPath对象之前尝试将“$ XML :: XPath :: Namespaces”设置为零,但这似乎没有任何区别。

以下是我将XML管道输入的简单脚本:

#! /bin/perl
use XML::XPath;
use XML::XPath::XMLParser;
use Getopt::Long;

$| = 1;

my $opt_file;
GetOptions("f|file=s" => \$opt_file);

$XML::XPath::Namespaces = 0;

my $xpath;
if ($opt_file ne '') {
    $xpath = XML::XPath->new(filename => $opt_file);
}
else {
    $xpath = XML::XPath->new(ioref => \*STDIN);
}

while (my $expr = shift @ARGV) {
    my $nodeset = $xpath->find($expr);
    if ($nodeset) {
        if ($opt_file ne '') {
            print $opt_file . ":\n";
        }
        my $node;
        for $node ($nodeset->get_nodelist) {
            print $node->string_value() . "\n";
        }
    }
}

这是一个示例命令行:

% echo "<ns3:abc xmlns:ns3=\"xxx\"><ns3:def>ghi</ns3:def></ns3:abc>" | xpathtext "//def"

我希望从中得到“ghi”,但我现在什么都没得到。

1 个答案:

答案 0 :(得分:1)

哇,那个模块很麻烦。

让我们暂时忘记你的问题,暂时使用$XML::XPath::Namespaces=1;(默认值)。

  1. $ perl -E'say q{<r><e>E</e></r>}' |
       xpathtext //e
    E
    

    正确。 null命名空间中有一个e元素。

  2. $ perl -E'say q{<r xmlns:p="http://n"><p:e>E</p:e></r>}' |
       xpathtext //e
    [nothing]
    

    正确。 null命名空间中没有e个元素。

  3. $ perl -E'say q{<r xmlns="http://n"><e>E</e></r>}' |
       xpathtext //e
    E
    

    不正确的。 null命名空间中没有e个元素,但是打印了一个。

  4. $ perl -E'say q{<r><e xmlns="http://n">E</e></r>}' |
       xpathtext //e
    E
    

    不正确的。 null命名空间中没有e个元素,但是打印了一个。

  5. $ perl -E'say q{<r xmlns:p="http://n"><p:e>E</p:e></r>}' |
       xpathtext //p:e
    E
    

    不正确的。这应该是一个错误,因为无法知道XPath中的p是否指向http://n命名空间。

  6. $ perl -E'say q{<r xmlns="http://n"><e>E</e></r>}' |
       xpathtext //p:e
    [nothing]
    

    不正确的。这应该是一个错误,因为无法知道XPath中的p是否指向http://n命名空间。

  7. 鉴于这种程度的懈怠,你遇到问题并不奇怪。


    现在让我们找出$XML::XPath::Namespace=0;的作用。

    $XML::XPath::Namespaces=0;重新运行上述程序后,我们发现答案“绝对没有”。

    我通过将魔法附加到变量来证实了这一点。永远不会使用该变量(在最新版本中,XML-XPath-1.13)!

    所以模块一半做了你想要的,一半做了应有的事情,没有明显的定制方法。