Perl libXML通过属性值查找节点

a0x5cqrl  于 2023-06-06  发布在  Perl
关注(0)|答案(4)|浏览(523)

我有一个非常大的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";
u0njafvf

u0njafvf1#

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

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

然后你的循环变成

my $node = $nodes_by_id{'1234'};

(And停止使用findvalue而不是getAttribute。)

flvtvl50

flvtvl502#

我认为您只需要对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')]

many中的一个XPath Tutorial

编辑:另一个有用的资源是“Perl XML::LibXML by Example”中的XPath expressions page。“试试吧!按钮链接到一个“XPathSandbox”页面,您可以在其中尝试示例并对其进行编辑。沙箱中还有一个“+”按钮,允许您处理自己的XML文档,包括带有名称空间的文档(默认的示例文件没有名称空间)。

lmyy7pcs

lmyy7pcs3#

如果你将为很多ID这样做,那么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。

1cosmwyk

1cosmwyk4#

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

相关问题