2013-11-24 53 views
1

我有一个xml数据显示如下。我想对这些数据进行一些操作。每当'entry'标签中缺少'colname'属性时,我的代码应该在'tgroup'标签中插入该属性采用'cols'属性的值。逻辑不工作在perl

<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

回答

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> 

UPDATE增加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; 
+0

确实运行这个脚本会覆盖源文件吗?我看到只有一个参数传递给这个.. –

+0

@RaviKumar:不会。它会将它打印到外壳。重定向到一个文件,如:'perl script.pl xmlfile> out_xmlfile' – Birei

+0

好的。在每一行中,如果有四个输入标签,则colname值应该从1增加到4.您的输出显示常量值。我该如何改变它? –

3

<row>(.*)</row>不尊重XML嵌套。即,你有什么样

<row> 
    ... 
    <row> 
     ... 
    </row> 
    <row> 
     ... 
    </row> 
</row> 

和外环只挑选了一切到第一内部行元素的结束和经营。

Lesson?不要使用正则表达式进行XML解析。它可以像Perl一样用扩展的RE语法来完成,但它很快就会变得非常麻烦。你最好使用合适的XML库。

+0

我几乎是新的perl和第一次在xml嵌套工作。感谢您的建议,我会记下这一点。 –

+5

,,你的船,轻轻顺流...... :) – toolic

+1

...如果你看到一个正则表达式解析它不要忘记尖叫! :) – Zaid