用 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')
.
我正在尝试按照以下内容从 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')
.