我正试图从这个xml示例中获取
<String Name="descResist">
<Description><![CDATA["resist_type_chimney"]]></Description>
<Flags>
<ParFlg_Child/>
</Flags>
<Value><![CDATA["90_min."]]></Value>
</String>
此
descResist;resist_type_chimney
descResist;90_min.
因此,基本上我需要提取CDATA内容并使用Name的值来连接它。
其中一个问题是,它并非总是在String
标记中......也可能是Integer
,Title
,Boolean
等...... < / p>
我试过这个
$ grep -o "Name=\".*\"\|<\!\[CDATA\[.*\]\]>" file.xml | sed 's/<\!\[CDATA\[\"\(.*
\)\"\]\]>/\1/'
给了我
Name="descResist"
resist_type_chimney
90_min.
如何使用Name string的值为下一行添加前缀?
喜欢
Name="descResist"
resist_type_chimney
90_min.
Name="anotherName"
foo_bar
Name="anoooother"
Name="notempty"
bar_foo
它有点复杂。
使用这样的XML也很好吗?还应该有任何嵌套的<tagType Name=...
所以我想这应该不是问题。
答案 0 :(得分:2)
我建议使用xml解析器。这里有一个使用XML::Twig
的{{3}}示例。
script.pl
的内容:
#!/usr/bin/env perl
use warnings;
use strict;
use XML::Twig;
my $twig = XML::Twig->new(
twig_handlers => {
'//*[@Name]' => sub {
for my $d ( $_->descendants( '#CDATA' ) ) {
(my $t = $d->text) =~ s/\A"(.*)"\z/$1/;
printf qq|%s;%s\n|, $_->att( 'Name' ), $t;
}
},
}
)->parsefile( shift );
像以下一样运行:
perl script.pl xmlfile
产量:
descResist;resist_type_chimney
descResist;90_min.
答案 1 :(得分:2)
试试这个:
#!/bin/bash
Name="InvalidName"
while read line; do
case "$line" in
Name=*) eval "$line" ;; # assuming $line is always bash-friendly Name="Value"
*) echo "$Name;$line" ;;
esac
done < <(egrep -o 'Name=".*"|<!\[CDATA\[.*?\]\]>' file.xml | sed -r 's/<!\[CDATA\["(.*)"\]\]>/\1/')
我稍微改变了你的命令以使用扩展正则表达式(这就是为什么它是“egrep”和“sed -r”)所以它更容易阅读。
我不喜欢我使用的那个eval,但是“export -n”在这种情况下做了一些奇怪的事情,并且为了避免使用eval,代码会变得不必要复杂。
如果你真的确定文本结构不会改变,那么在Bash中“解析”XML是可以的。一旦有人决定通过将XML全部折叠成一行来“优化”XML,你就会有点干杯。
修改强>
这是一个没有丑陋eval的脚本:
#!/bin/bash
Name="InvalidName"
while read line; do
case "$line" in
Name=*) export -n "$line" ;; # assuming $line is always bash-friendly Name=Value
*) echo "$Name;$line" ;;
esac
done < <(egrep -o 'Name=".*"|<!\[CDATA\[.*?\]\]>' file.xml | sed -r 's/<!\[CDATA\["(.*?)"\]\]>/\1/; s/Name="(.*)"/Name=\1/')