【问题标题】:Parse XML file with Perl使用 Perl 解析 XML 文件
【发布时间】:2017-10-28 00:08:05
【问题描述】:

我正在尝试按照以下方式从 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 中没有 set 元素,但您的 xpath 表达式需要一个。我现在不能尝试,但你应该对//DataSet[@seriesName= "Actual" ]/Data/Value 很好,然后不要使用$_-&gt;att,因为Value 不是属性。使用上面的 xpath,您将拥有节点,并且可以访问 text 属性。我不记得如何了,请查看文档。

标签: xml perl xml-twig


【解决方案1】:

这里有很多误解。首先,您的 XML 无效。我知道这只是一个示例,但最好给我们一个有效的(如果缩减)示例以供使用。从第一个元素中省略开头的&lt; 让我觉得你没有以你应该的精确程度看待这个!

那么 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;
}

请注意,我在原帖中不小心遗漏了另一个更改 - 因为“值”不是属性,所以我使用了 $_-&gt;text 而不是您的 $_-&gt;att('Value')

【讨论】:

  • 感谢 cmets(是的,我希望提高我的编程技能)我已按照指示修改了脚本。但是,即使使用 /Data/Value 或简单地使用 /Value,我也无法提取所需的数字。我添加了更多的 XML,但它非常大,所以我希望这次捕获足够多。
  • 您的示例 XML 仍然无效。有一个&lt;DataSet&gt; 元素没有对应的&lt;/DataSet&gt;。请多加小心。我已经更新了我的答案,包括我的测试 XML 以及我编写的代码。这给出了正确的输出。
  • 感谢您的帮助。我添加了文件输出语法,我非常高兴。
猜你喜欢
  • 2013-04-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-11
  • 2013-07-17
  • 1970-01-01
  • 2011-04-13
  • 2012-03-27
相关资源
最近更新 更多