Perl libXML按属性值

时间:2015-07-05 14:47:02

标签: perl libxml2

我有非常大的XML文档,我正在迭代。 XML主要使用属性而不是节点值。我可能需要在文件中找到许多节点来拼凑一组信息。它们通过不同的ref标签值绑定在一起。目前,每次我需要找到一个节点来提取数据时,我循环遍历整个XML并对属性进行匹配以找到正确的节点。是否有更有效的方法来选择给定属性值的节点而不是不断循环和比较?我目前的代码太慢,几乎没用。

目前,我在同一个文件中为许多不同的节点和属性组合多次执行此类操作。

my $searchID = "1234";
foreach my $nodes ($xc->findnodes('/plm:PLMXML/plm:ExternalFile')) {
    my $ID      = $nodes->findvalue('@id');
    my $File    = $nodes->findvalue('@locationRef');
    if ( $searchID eq $ID ) {
        print "The File Name = $File\n";
    }
}

在上面的示例中,我正在循环并使用" if"比较ID匹配。我希望我可以做下面这样的事情来匹配节点的属性而不是...并且它会更有效然后循环吗?

my $searchID = "1234";
$nodes = ($xc->findnodes('/plm:PLMXML/plm:ExternalFile[@id=$searchID]'));
my $File    = $nodes->findvalue('@locationRef');
print "The File Name = $File\n";

4 个答案:

答案 0 :(得分:2)

执行一次传递,以便以更方便的格式提取所需信息或构建索引。

new BigDecimal("10000");
new BigDecimal(10000);

然后你的循环变成

my %nodes_by_id;
for my $node ($xc->findnodes('//*[@id]')) {
    $nodes_by_id{ $node->getAttribute('id') } = $node;
}

(并停止使用my $node = $nodes_by_id{'1234'}; 代替findvalue。)

答案 1 :(得分:2)

如果你要为很多身份证做这件事,那么ikegami的答案值得一读。

  

我希望我能做下面这样的事情,只是按属性匹配

     

...

$nodes = ($xc->findnodes('/plm:PLMXML/plm:ExternalFile[@id=$searchID]'));

排序。

对于给定的ID,是的,您可以

$nodes = $xc->findnodes("/plm:PLMXML/plm:ExternalFile[\@id=$searchID]");

...前提是$searchID已知为数字。请注意perl中的双引号表示变量插值,因此您应该转义@id因为它是文字字符串的一部分,而不是perl数组,而您希望$searchID的值成为xpath字符串,因此不会被转义。

另请注意,在这种情况下,您在标量上下文中要求它将具有XML::LibXML::Nodelist对象,而不是实际节点,也不是arrayref;对于后者,你需要使用方括号而不是圆形括号,就像我在下一个例子中所做的那样。

或者,如果您的搜索ID可能不是数字,但您确定将其放入XPath字符串是安全的(例如,没有任何引号),您可以执行以下操作:

$nodes = [ $xc->findnodes('/plm:PLMXML/plm:ExternalFile[@id="' . $searchID . '"]') ];
print $nodes->[0]->getAttribute('locationRef'); # if you're 100% sure it exists

请注意,结果字符串会将值括在引号中。

最后,可以直接跳到:

print $xc->findvalue('/plm:PLMXML/plm:ExternalFile[@id="' . $searchID . '"]/@locationRef');

...如果您知道只有一个节点具有该ID。

答案 2 :(得分:1)

如果您的文档的DTD将id属性声明为DTD ID,并且您确保在解析文档时读取了DTD,则可以访问具有特定ID的元素通过$doc->getElementById($id)有效率。

答案 3 :(得分:1)

我认为你只需要对XPath表达式做一些研究。例如,你可以这样做:

my $search_id = "1234";
my $query = "/plm:PLMXML/plm:ExternalFile/[\@id = '$search_id']";
foreach my $node ($xc->findnodes($query)) {
    # ...
}

在XPath表达式中,您还可以组合多个属性检查,例如:

[@id = '$search_id' and contains(@pathname, '.pdf')]

XPath Tutorial many