使用Perl解析XML文件

时间:2017-05-27 03:37:41

标签: xml perl xml-twig

我正在尝试按照以下方式从XML文件中提取值:

  <?xml version="1.0" encoding = "UTF-8" ?>
  <!-- SAP Data Services generated XML -->
  <!-- 2017-05-26.22:12:03(409,091)[1] -->

 <Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <CreatedAt>2017-05-26T22:12:11</CreatedAt>
 <CreateBy>BJOB_ODS_WF5MD_WEBSITE_FILES_5MIN_DATA</CreateBy>
 <StartDate>2017-05-21T00:00:00</StartDate>
  <DataSet Series = "5_Minute" ><Data><Value>10875.60</Value>
  </Data>
 ....
 <DataSet Series = "Actual" ><Data><Value>11150.00</Value>
  </Data>
 <Data><Value>10700.00</Value>  
</Data>
<Data><Value>10450.00</Value>
</Data>
   ...
</Data>
 </DataSet> 
</Root>

希望以下输出到csv但不喜欢下面的脚本:

11150.00

10700.00

10450.00

 ****SCRIPT
use warnings;
use strict;
use XML::Twig;
#<DataSet Series = "Actual" ><Data><Value>11112.60</Value

my $file = '/var/data/Actual.xml' ||die $!;

my $t=XML::Twig->new();
$t->parsefile( $file );

# my @sets = $t->findnodes('//DataSet[@seriesName= "Actual" ]/set');
# I CHANGED THE ABOVE AND MODIFIED AS SHOWN BELOW

 my @sets = $t->findnodes('//DataSet[@Series= "Actual" ]/Value');    
 if (@sets) {
  my $outfile = '/var/csv/actual.csv';
  open my $out, ">", $outfile or die "Could not open $outfile: $!";  
  print { $out } $_->att('Value')."\n" for @sets;
 } 

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:2)

这里有一些误解。首先,您的XML无效。我知道它只是一个例子,但是给我们一个有效的(如果减少的)示例是很好的。从第一个元素中省略开头<让我觉得你并没有以你应该达到的精确程度来看待它!

然后,XPath表达式与您正在解析的XML几乎没有关系。正如他在评论中提到的simbabque,你指的是那些不会出现在你的XML中的元素,所以没有什么是匹配的,这并不奇怪。

  • seriesName属性名为Series
  • 没有set元素。您需要Data/Value

这似乎给了你你想要的东西(它非常接近simbabque的建议,但他错过了seriesName问题。)

my @sets = $t->findnodes('//DataSet[@Series="Actual"]/Data/Value');

程序员需要处理精确度和准确性。也许你需要解决这个问题: - )

更新:以下是我正在使用的测试XML。它基于您的XML,但我修复了一些明显的错误。

<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <CreatedAt>2017-05-26T22:12:11</CreatedAt>
 <CreateBy>BJOB_ODS_WF5MD_WEBSITE_FILES_5MIN_DATA</CreateBy>
 <StartDate>2017-05-21T00:00:00</StartDate>
 <DataSet Series = "5_Minute" >
   <Data><Value>10875.60</Value></Data>
 </DataSet>
 <DataSet Series = "Actual" >
  <Data><Value>11150.00</Value></Data>
  <Data><Value>10700.00</Value></Data>
  <Data><Value>10450.00</Value></Data>
 </DataSet>
</Root>

以下是我测试过的代码。我稍微简化了你的代码,把文件名作为参数并将输出写入STDOUT(我不明白为什么这么多人在很多时候对文件名进行硬编码)。

#!/usr/bin/perl

use warnings;
use strict;
use XML::Twig;

my $file = shift   or die "No file given\n";

my $t=XML::Twig->new();
$t->parsefile( $file );

my @sets = $t->findnodes('//DataSet[@Series="Actual"]/Data/Value');

if (@sets) {
  print $_->text, "\n" for @sets;
}

请注意,我在原始帖子中意外省略了另一项更改 - 因为&#39;价值&#39;我不是$_->text而是使用$_->att('Value')