gpt4 book ai didi

xml - 使用 LibXML 和 XPath 查找带冒号的节点(本地命名空间)

转载 作者:行者123 更新时间:2023-12-02 20:55:50 30 4
gpt4 key购买 nike

我正在尝试获取属性 @id1来自<Incoming>在下面的 XML 中:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Incomings xmlns:ns2="http://testme.org/foo/schema">
<Incoming id1="6bbaec22" id2="928c2081">
<ns2:Address>fubar@test.com</ns2:Address>
</Incoming>
</Incomings>

我可以传入的唯一信息是电子邮件地址 fubar@test.com

我正在使用XML::LibXMLXML::LibbXML::XPathContext如下:

my $dom = XML::LibXML->new->parse_file( $xml_file );  # XML contains as above
my $xpc = XML::LibXML::XPathContext->new( $dom->documentElement );
$xpc->registerNs('x', 'http://testme.org/foo/schema');

my $email = 'fubar@test.com';
my $xpath = "/x:Incomings/x:Incoming/x:ns2:Address[text()='$email']/../\@id1";
my @nodes = $xpc->findnodes( $xpath );

但它总是在 $xpath 中给我一个无效的表达式围绕 ns2:Address

上面我犯了什么错误?如果节点名称仅为 <Address>然后从我的 $xpath 中删除 ns2:语句给了我正确的值 @nodes .

谢谢!

最佳答案

我认为这里有两个问题 - 首先,xpath 表达式查找节点。您可以根据属性的存在性和内容进行搜索,但 findnodes 将为您提供元素,而不是内容。

其次 - 不能在 XML 中嵌套命名空间。 x:ns2:Address 无效。您实际上需要在那里注册您的 x 命名空间吗?您可能根本不需要。 (例如,基于您的小 XML 片段)。

我可以提供替代选择吗?因为您使用的是 perl,所以您实际上不一定需要通过 xpath 表达式执行所有操作。

我可能会想到 findnodes 后跟 grep:

注意:使用 XML::Twig 进行说明 - 非常肯定 XML::LibXML 中也有类似的东西。

#!/usr/bin/env perl
use strict;
use warnings;
use XML::Twig;

my $twig = XML::Twig->new( 'pretty_print' => 'indented_a' )->parse( \*DATA );

my @elt_list = grep { $_->trimmed_text =~ m{fubar\@test.com} }
( $twig->findnodes('//ns2:Address') );

foreach my $elt (@elt_list) {
print $elt -> parent -> att('id1');
}


__DATA__
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Incomings xmlns:ns2="http://testme.org/foo/schema">
<Incoming id1="6bbaec22" id2="928c2081">
<ns2:Address>fubar@test.com</ns2:Address>
</Incoming>
</Incomings>

我还要注意 - 您的 xpath 允许您查找元素 - 而不是属性 - 因此您可以选择“具有 id1 属性的元素,如下所示:

my @elt_list = ( $twig->findnodes("//ns2:Address[string()='$email']/../.[\@id1]") );

foreach my $elt (@elt_list) {
print $elt -> att('id1');
}

取决于您希望 findnodes 搜索的具体程度。根据您在该片段中提供的内容,您已经变得过于复杂,并且可以简单地执行以下操作:

use XML::Twig;

my $twig = XML::Twig->parsefile('your_file.xml');
print $twig -> findnodes('//Incoming',0)->att('id1'),"\n";

或者:

#!/usr/bin/env perl
use strict;
use warnings;
use XML::LibXML;

my $xml = XML::LibXML->new->parse_file( 'sample2.xml' );
foreach my $node ( $xml -> findnodes( '//Incoming' ) ) {
print $node ->getAttribute('id1'), "\n";
}

或者进行一些 grep 操作:

#!/usr/bin/env perl
use strict;
use warnings;
use XML::LibXML;

my $email = 'fubar@test.com';
my $xml = XML::LibXML->new->parse_file( 'sample2.xml' );
foreach my $node ( grep { $_ -> textContent =~ m{$email} } $xml -> findnodes( '//Incoming' ) ) {
print $node ->getAttribute('id1'), "\n";
}

如果您特别想使用 x 命名空间 - 这可行:

#!/usr/bin/env perl
use strict;
use warnings;
use XML::LibXML;

my $xml = XML::LibXML->new->parse_file('sample2.xml');
my $xpc = XML::LibXML::XPathContext->new( $xml->documentElement );
$xpc->registerNs( 'x', 'http://testme.org/foo/schema' );

my $email = 'fubar@test.com';
my ( $id1 ) = map { $_ -> getAttribute('id1') // () } $xpc->findnodes("/Incomings/Incoming/x:Address[text()='$email']/..");
print $id1,"\n";

(如果我模拟一些带有多个“传入”节点的 XML 以选择第一个具有正确电子邮件地址的节点,也可以工作。注意 // 是 perl 5.10 及以上版本,并且以“定义”为条件'。您可能可以在旧版本上用 || 替换它,即“true/false” - 唯一存在差异的地方是空字符串和零)

关于xml - 使用 LibXML 和 XPath 查找带冒号的节点(本地命名空间),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32221867/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com