-2

说说你如何使用 perl 解析这个特定的 XML

一点背景知识:我正在编写一个 perl 脚本,其中我将 XML(datamod) 分成两个 XML 文件。

示例:现有 XML

<Root>
 <Top>
  <Module name="ALU">
   <input name="po_ctrl"/>
   <bidirection name="add"/>
  </Module>
  <Module name="Po_ctrl">
   <input name="ctrl"/>
   <output name="ctrlbus"/>
   <bidirection name="add"/>
  </Module>
  <input name="add"/>
  <input name="clk"/>
  <input name="da_in"/>
  <output name="da_out"/>
  <bidirection name="ctrl"/>
 </Root>
</Top>

下面是编写的 perl 片段

 open(IN_FILE, "<datamod.xml") or die "Cant open input file";
 open(TM1_FILE, ">tm1.xml") or die "Cant Open tm1.xml";
 open(TM2_FILE, ">tm2.xml") or die "Cant Open tm2.xml"; 
 my $chk = 0;
 while(my $line = <IN_FILE>){
 $line =~ s/^\s+//;
 @xwords = split(" ",$line);
 if($xwords[0] ne "<Module" and $xwords[0] ne "</Module>"  and $chk ==0) {
   print TM1_FILE $line;
  }  
  else {
   print TM2_FILE $line;
   $chk = 1;
  }   
 if($xwords[0] eq "</Module>" and $chk == 1) {
  $chk = 0;
 }  
}
close TM1_FILE;
close TM2_FILE;

预期输出到两个临时文件

临时文件 1:

   <Root>
      <Top>
       <input name="add"/>
       <input name="clk"/>
       <input name="da_in"/>
       <output name="da_out"/>
       <bidirection name="ctrl"/>
      </Top>
    </Root>

临时文件 2

<Root>
 <Top>
  <Module name="ALU">
   <input name="po_ctrl"/>
   <bidirection name="add"/>
  </Module>
  <Module name="Po_ctrl">
   <input name="ctrl"/>
   <output name="ctrlbus"/>
   <bidirection name="add"/>
  </Module>
</Root>
</Top>

注意:我正在使用该XML::Simple模块,因为 Perl 脚本是在其中编写的,并且转换为任何其他 XML 模块都很乏味。

任何帮助表示赞赏,请发布重写的片段!

4

2 回答 2

1

不要对 XML 使用正则表达式。XML 是一种递归数据结构,虽然从技术上讲,您可以使用正则表达式进行递归,但它会导致代码变脏。因此,实际上您最终会遇到一些非常有选择性的hackery,有一天会神秘地破坏,因为完全有效的XML 更改不再适合您的正则表达式。

另外:出于同样的原因,请勿使用 XML::Simple 。(尽管您说您在问题中使用它,但在您发布的代码中没有迹象表明您这样做了)。

使用适当的解析器,您尝试做的事情变得非常简单。我喜欢XML::TwigXML::LibXML可能更好,但学习曲线更陡峭。两者都不太容易出现未来的痛苦和伪劣代码。

您正在尝试做的似乎是拆分 XML,并放入modules一个,并将“其他所有内容”放入另一个中。这是这样完成的XML::Twig

#!/usr/bin/env perl
use strict;
use warnings;

use XML::Twig;

#parse your input
my $twig = XML::Twig->new->parsefile( 'datamod.xml' ); 

#create a new 'modules' document. 
my $modules = XML::Twig->new;
#create a root
$modules->set_root( XML::Twig::Elt->new('Root') );
#create a "Top" element. (You can compound this if you want)
my $top = $modules->root->insert_new_elt('Top');
#set output format (note - this can break in specific edge cases - your XML
#doesn't seem to be one of those). 
$modules->set_pretty_print('indented_a');

#find all the "<Module>" elements. 
foreach my $module ( $twig->findnodes('//Module') ) {
    #cut from old doc
    $module->cut;
    #paste into new. last_child ensures same ordering.
    $module->paste( 'last_child', $top );
}

#print the output to a file.  
open ( my $output, '>', 'tm1.xml' ) or warn $!; 
print {$output} $twig -> sprint; 
close ( $output ); 

open ( my $second_output, '>', 'tm2.xml' ) or warn $!;
print {$second_output} $modules -> sprint; 
close ( $second_output ); 

注意 - 这里有更多关于组装新 XML 文档的内容:Assembling XML in Perl

您可能需要考虑设置编码和版本。

于 2016-01-06T12:19:47.260 回答
1

由于您没有包含任何代码,或者您的数据目前如何,我将建议这个简单的 hack。只需在解析 XML 之前将其添加为文本。

use strict;
use warnings;

my $xml = <your xml here>;
$xml = "<Root>\n" . $xml . "</Root>\n";
于 2016-01-05T09:42:23.620 回答