逻辑不在perl中工作

时间:2013-11-24 12:47:47

标签: regex perl

我有一个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;
        }
    }

问题是,当同时存在两行时,只有一行得到更新。当我调试时,我发现值正在正确更新,但在写入输出文件时,它们被忽略。我无法找到代码中控件出错的位置。对此的任何帮助都非常感谢。提前谢谢!

以下是代码的输出。突出显示的数据未更新。

Here is the output of the code

2 个答案:

答案 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库。