如何使用重复的同级节点组导航XML
我使用的是Perl和XML::LibXML,我必须处理的XML如下所示:如何使用重复的同级节点组导航XML,xml,xpath,xml-parsing,xml-libxml,Xml,Xpath,Xml Parsing,Xml Libxml,我使用的是Perl和XML::LibXML,我必须处理的XML如下所示: <PARAM NAME = "A"><VALUE>1</VALUE> <PARAM NAME = "B"><VALUE>3</VALUE> <PARAM NAME = "C"><VALUE>43</VALUE> <PARAM NAME = "A"><VALUE>6</VALUE>
<PARAM NAME = "A"><VALUE>1</VALUE>
<PARAM NAME = "B"><VALUE>3</VALUE>
<PARAM NAME = "C"><VALUE>43</VALUE>
<PARAM NAME = "A"><VALUE>6</VALUE>
<PARAM NAME = "B"><VALUE>3</VALUE>
<PARAM NAME = "C"><VALUE>13</VALUE>
.
.
.
my @attributes = (
'./PARAM[@NAME = "A"]/VALUE',
'./PARAM[@NAME = "B"]/VALUE',
.
.
);
我已将文字节点名称放入如下数组:
<PARAM NAME = "A"><VALUE>1</VALUE>
<PARAM NAME = "B"><VALUE>3</VALUE>
<PARAM NAME = "C"><VALUE>43</VALUE>
<PARAM NAME = "A"><VALUE>6</VALUE>
<PARAM NAME = "B"><VALUE>3</VALUE>
<PARAM NAME = "C"><VALUE>13</VALUE>
.
.
.
my @attributes = (
'./PARAM[@NAME = "A"]/VALUE',
'./PARAM[@NAME = "B"]/VALUE',
.
.
);
然后使用findnodes()和findvalue()以及这些xpath文本作为foreach循环中的参数,错误地试图获取一组值以写入记录。
当然,findnodes()是错误的,因为它在循环的每次传递中都会获得满足条件的所有节点(正如它应该做的那样),而findvalues()是错误的,因为它实际上做了相同的事情,只是将所有类似的命名节点值串联在一起
由于这个文件的结构是这样的,我认为没有办法捕获“A到C”节点/值,写一条记录,然后重复…至少在不检查每个节点以确定它是否是“最后一个”(“C”)的情况下是这样的。基本上,我需要将其作为一个纯文本文件进行处理。您没有提供您使用的语言,但它似乎是perl。基本上,获取所有
元素(分别是它们的文本节点),然后在它们上面循环,每次读取三个值
在某种程度上是一种伪代码:
@attributes = xpath('//PARAM/VALUE');
for ($i = 0; i < length(@attributes); i += 3)
push @records (@attributes[$i], @attributes[$i + 1], @attributes[$i + 2])
@attributes=xpath('//PARAM/VALUE');
对于($i=0;i
因此,您应该得到一个数组数组(当然,您也可以返回一个哈希数组)。如果您只是想要输出,请使用上面的模式并适当调用
printf
,而不是push
以下是我采用的一种有效方法:
foreach my $parameter ( $raid_group->findnodes('PARAM')) {
my $name = $parameter->findvalue('@NAME);
my $value = $parameter->findvalue('VALUE');
if ($name eq $first_name_in_set ){
[do stuff]
}
}
这是一个用螺丝刀凿凿子的例子,我认为这是权宜之计,但仅此而已。您的数据实际上不是有效的XML,因为每个参数都没有结束标记。因此,您需要在运行XML解析器之前清理数据,或者使用正则表达式 下面使用正则表达式来解析任意数量的字段和值:
use strict;
use warnings;
my %seen_header;
my @headers;
my @data = {};
while (<DATA>) {
if (m{<PARAM NAME = "(.*?)"><VALUE>(.*?)</VALUE>}i) {
my $name = $1;
my $val = $2;
push @headers, $name if ! $seen_header{$name}++;
push @data, {} if exists $data[-1]{$name};
$data[-1]{$name} = $val;
} else {
warn "Unrecognized format at line $.: $_"
}
}
print "@headers\n";
print join(' ', map {$_ // ''} @{$_}{@headers}), "\n" for (@data);
__DATA__
<PARAM NAME = "A"><VALUE>1</VALUE>
<PARAM NAME = "B"><VALUE>3</VALUE>
<PARAM NAME = "C"><VALUE>43</VALUE>
<PARAM NAME = "A"><VALUE>6</VALUE>
<PARAM NAME = "B"><VALUE>3</VALUE>
<PARAM NAME = "C"><VALUE>13</VALUE>
也可以将此代码修改为使用XML解析器,但如果您需要,我将由您决定。谢谢。源文件不在我的控制之下,因此我需要假设属性节点的“集合”可以更改——事实上,我刚刚发现它们可以更改。我所做的是: