用 Perl 解析 XML 文件

Parse XML file with Perl

我正在尝试按照以下内容从 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;
 } 

如有任何帮助,我们将不胜感激。

这里有不少误会。首先,您的 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;
}

请注意,我做了另一项更改,我不小心从我的原始 post 中遗漏了 - 因为 'Value' 不是属性,我使用 $_->text 而不是你的$_->att('Value').