Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用xmlstarlet在xml上迭代并输出父节点和子节点值_Xml_Bash_Xmlstarlet - Fatal编程技术网

使用xmlstarlet在xml上迭代并输出父节点和子节点值

使用xmlstarlet在xml上迭代并输出父节点和子节点值,xml,bash,xmlstarlet,Xml,Bash,Xmlstarlet,我在多个XML文件中使用此格式: <bad> <objdesc> <desc id="butwba10.1.wc.01" dbi="BUTWBA10.1.1.WC"> <physdesc>adfa;sdfkjad</physdesc> <related objectid="bb435.1.comdes.02"/> <related objectid="but614r.

我在多个XML文件中使用此格式:

<bad>
 <objdesc>
 <desc id="butwba10.1.wc.01" dbi="BUTWBA10.1.1.WC">
        <physdesc>adfa;sdfkjad</physdesc>
        <related objectid="bb435.1.comdes.02"/>
        <related objectid="but614r.1.penc.01"/>
        <related objectid="but611.1.wc.01"/>
        <related objectid="but612.1.wd.01"/>
        <related objectid="bb515.1.comb.12"/>
 </desc>
 <desc id="butwba10.1.wc.02" dbi="BUTWBA10.1.2.WC">
        <physdesc>alkdjfa;sfjsdf</physdesc>
        <related objectid="but621r.1.penc.01"/>
        <related objectid="bb435.1.comdes.03"/>
 </desc>
 </objdesc>
 </bad>
我有一个bash脚本,它使用xmlstarlet迭代目录中的xml文件,但它会转储最后一个desc id之后的所有“相关值”。它需要将每个desc id与每一组“相关”值关联起来。它需要包含每个id的dbi值

#!/bin/bash

for x in *.xml
do
    id=$(xml sel -t -v '//bad/objdesc/desc/@id' "$x")
    arr=( $(xml sel -t -v '//bad/objdesc/desc/related/@objectid' "$x") )
    cat<<EOF >> new_file
$id related="$(perl -e 'print join ",", @ARGV' "${arr[@]}")"
EOF
done
#/bin/bash
对于*.xml中的x
做
id=$(xmlsel-t-v'//bad/objdesc/desc/@id''$x)
arr=($(xml sel-t-v'//bad/objdesc/desc/related/@objectid''x'))
cat新文件
$id related=“$(perl-e'打印连接',”,@ARGV'${arr[@]}”)
EOF
完成
#/bin/bash
对于*.xml中的x;做
count=$(xmlsel-t-v'count(//bad/objdesc/desc/@id)“$x”)

for((i=1;i同意sputnick的观点,XSLT是正确的工具。不过,使用XML令牌解析器的perl答案具有只需处理一次文件而不必重复调用xmlstarlet的优点:

#!perl

use strict;
use warnings;
use XML::Parser;

my (@related, @desc); # boo, global variables

sub start {
    my ($x, $elem, %attrs) = @_;
    if ($elem eq "desc") {
        @desc = @attrs{'id', 'dbi'};
        @related = ();
    }
    elsif ($elem eq "related") {
        push @related, $attrs{objectid};
    }
}

sub end {
    my ($x, $elem) = @_;
    if ($elem eq "desc") {
        printf qq{%s dbi="%s" related="%s"\n}, @desc, join(', ', @related);
    }
}

my $parser = XML::Parser->new( Handlers => {Start => \&start, End => \&end} );
$parser->parsefile($ARGV[0]);
在行动中:

$ perl parse.pl file 
butwba10.1.wc.01 dbi="BUTWBA10.1.1.WC" related="bb435.1.comdes.02, but614r.1.penc.01, but611.1.wc.01, but612.1.wd.01, bb515.1.comb.12"
butwba10.1.wc.02 dbi="BUTWBA10.1.2.WC" related="but621r.1.penc.01, bb435.1.comdes.03"

很好,但是我们有3个调用
xmlstarlet
。这不是最优的,但它是有效的:)调用perl连接的另一个替代方法是
join=$(IFS=,;echo“${arr[*]}”)
——仍然需要生成子shell思想,或者在当前shell中,
printf-v join”%s,“${arr[@}”;join=${join%,}
三次使用xmlstarlet的原因是,在SO的另一篇帖子中,要求不够明确。事情一点一点地发生了=)>因为需要时间才能给出正确的解决方案+1
#!perl

use strict;
use warnings;
use XML::Parser;

my (@related, @desc); # boo, global variables

sub start {
    my ($x, $elem, %attrs) = @_;
    if ($elem eq "desc") {
        @desc = @attrs{'id', 'dbi'};
        @related = ();
    }
    elsif ($elem eq "related") {
        push @related, $attrs{objectid};
    }
}

sub end {
    my ($x, $elem) = @_;
    if ($elem eq "desc") {
        printf qq{%s dbi="%s" related="%s"\n}, @desc, join(', ', @related);
    }
}

my $parser = XML::Parser->new( Handlers => {Start => \&start, End => \&end} );
$parser->parsefile($ARGV[0]);
$ perl parse.pl file 
butwba10.1.wc.01 dbi="BUTWBA10.1.1.WC" related="bb435.1.comdes.02, but614r.1.penc.01, but611.1.wc.01, but612.1.wd.01, bb515.1.comb.12"
butwba10.1.wc.02 dbi="BUTWBA10.1.2.WC" related="but621r.1.penc.01, bb435.1.comdes.03"