我有一个xml数据如下所示。我想对这些数据进行一些操作。每当'entry'标记中缺少'colname'属性时,我的代码应插入该属性,并使用'tgroup'标记中'cols'属性的值。
<tbl ID="I78">
<table colsep="0" frame="none" rowsep="0">
<tgroup cols="4">
<tbody valign="top">
<row>
<entry>i.</entry>
<entry>181.10</entry>
<entry>An inmate shall comply with the dispositions imposed by a hearing officer in a Tier I, Tier II and Tier III hearings.</entry>
<entry>I, II, III</entry>
</row>
</tbody>
</tgroup>
</table>
</tbl>
<tbl ID="I93">
<table colsep="0" frame="none" rowsep="0">
<tgroup cols="4">
<tbody>
<row>
<entry align="center"><ital>Pledge number</ital></entry>
<entry align="center"><ital>Date</ital></entry>
<entry align="center"><ital>R</ital></entry>
<entry><ital>A or S</ital></entry>
</row>
<row>
<entry><ital>Disposition column</ital></entry>
<entry>(<ital>Renewed</ital>)</entry>
<entry>(<ital>Renewed</ital>)</entry>
</row>
<row>
<entry>(<ital>Auction Sale</ital>)</entry>
</row>
</tbody>
</tgroup>
<eos></eos>
</table>
<eop></eop>
</tbl>
我的代码如下所示:
foreach $line (@data){
if($line =~ /<tgroup(.*?)cols=\"(.*?)\">/i){
$colcount=$2;
print "\nTgroup tag found... no of cols are $colcount";
}
$templine=$line;
my $temp2line;
while($templine=~ /<tbody(.*?)>(.*?)<\/tbody>/){
$temp2line=$2;
while($temp2line=~ /<row>(.*?)<\/row>/){
$rowdata=$1;
$rowdataforfinalreplacing=$rowdata;
$temprowdata=$rowdata;
while($rowdata=~/<entry align="center">/i){
for ($i; $i<= $colcount; $i++){
$temprowdata=~s/<entry align="center">/<entry align="center" colname=\"$i\">/i;
print "\ni value :$i";
}
$rowdata=~s/<entry(.*?)<\/entry>//;
}
while($rowdata=~/<entry>/i){
for (my $i=1; $i<= $colcount; $i++){
$temprowdata=~s/<entry>/<entry colname=\"$i\">/i;
}
$rowdata=~s/<entry>(.*?)<\/entry>//;
}
$temp2line=~s/<row>(.*?)<\/row>//i;
$line=~s/$rowdataforfinalreplacing/$temprowdata/sgi;
}
}
问题是,当同时存在两行时,只有一行得到更新。当我调试时,我发现值正在正确更新,但在写入输出文件时,它们被忽略。我无法找到代码中控件出错的位置。对此的任何帮助都非常感谢。提前谢谢!
以下是代码的输出。突出显示的数据未更新。
答案 0 :(得分:6)
请不要使用正则表达式来解析xml
数据。这是一种痛苦。
说,您的xml
数据格式不正确,因为您有多个root
标记。我添加了<root>
以使其形成良好。
这里有一个XML::Twig
的例子:
#!/usr/bin/env perl
use warnings;
use strict;
use XML::Twig;
my ($colname);
XML::Twig->new(
start_tag_handlers => {
'tgroup' => sub { $colname = $_->att('cols') },
},
twig_handlers => {
'entry' => sub { $_->set_att('colname', $colname) },
},
pretty_print => 'indented',
)->parsefile(shift)->print;
像以下一样运行:
perl script.pl xmlfile
产量:
<root>
<tbl ID="I78">
<table colsep="0" frame="none" rowsep="0">
<tgroup cols="4">
<tbody valign="top">
<row>
<entry colname="4">i.</entry>
<entry colname="4">181.10</entry>
<entry colname="4">An inmate shall comply with the dispositions imposed by a hearing officer in a Tier I, Tier II and Tier III hearings.</entry>
<entry colname="4">I, II, III</entry>
</row>
</tbody>
</tgroup>
</table>
</tbl>
<tbl ID="I93">
<table colsep="0" frame="none" rowsep="0">
<tgroup cols="4">
<tbody>
<row>
<entry align="center" colname="4">
<ital>Pledge number</ital>
</entry>
<entry align="center" colname="4">
<ital>Date</ital>
</entry>
<entry align="center" colname="4">
<ital>R</ital>
</entry>
<entry colname="4">
<ital>A or S</ital>
</entry>
</row>
<row>
<entry colname="4">
<ital>Disposition column</ital>
</entry>
<entry colname="4">(<ital>Renewed</ital>)</entry>
<entry colname="4">(<ital>Renewed</ital>)</entry>
</row>
<row>
<entry colname="4">(<ital>Auction Sale</ital>)</entry>
</row>
</tbody>
</tgroup>
<eos></eos>
</table>
<eop></eop>
</tbl>
</root>
更新以增加colname
属性。见评论。
#!/usr/bin/env perl
use warnings;
use strict;
use XML::Twig;
my ($colname, $n);
XML::Twig->new(
start_tag_handlers => {
'tgroup' => sub { $colname = $_->att('cols') },
'row' => sub { $n = 1 },
},
twig_handlers => {
'entry' => sub { $_->set_att('colname', $n++) },
},
pretty_print => 'indented',
)->parsefile(shift)->print;
答案 1 :(得分:3)
您的<row>(.*)</row>
不尊重XML嵌套。即,你有像
<row>
...
<row>
...
</row>
<row>
...
</row>
</row>
并且外部循环仅拾取第一个内部行元素末尾的所有内容并对其进行操作。
课?不要使用正则表达式进行XML解析。它可以用像Perl这样的语言和扩展的RE语法来完成,但很快就会变得非常混乱。你最好使用合适的XML库。