不要将 XML 视为基于行的数据,因为它不是。相反,使用一个好的 XML 解析器,Perl 有很多。
不要使用 XML::Simple!
它自己的文档说它已被弃用:
不鼓励在新代码中使用此模块。其他模块也可以提供更直接和一致的接口。特别是,强烈推荐使用 XML::LibXML。
这个模块的主要问题是大量的选项以及这些选项交互的任意方式——通常会产生意想不到的结果。
所以我们将使用XML::LibXML
模块,它与libxml2
GNOME 项目的外部库接口。这样做的好处是我们可以使用 XPath 表达式来查询我们的数据。要读取或写入 CSV,Text::CSV
应使用该模块。
use strict; use warnings;
use XML::LibXML;
use Text::CSV;
# load the data
my $data = XML::LibXML->load_xml(IO => \*STDIN) or die "Can't parse the XML";
# prepare CSV output:
my $csv = Text::CSV->new({ binary => 1, escape_char => "\\", eol => "\n" });
# Text::CSV doesn't like bareword filehandles
open my $output, '>&:utf8', STDOUT or die "Can't dup STDOUT: $!";
my @cols = qw/ name left width /; # the column names in the CSV
my @attrs = qw/ Name Left Width /; # the corresponding attr names in the XML
# print the header
$csv->print($output, \@cols);
# extract data
for my $label ($data->findnodes('//Label')) {
my @fields = map { $label->getAttribute($_) } @attrs;
$csv->print($output, \@fields);
}
测试数据(我冒昧地关闭了Width attr的值):
<foo>
<Label Name="lblIncidentTypeContent" Increasable="true" Left="140" Top="60"
Width="146" SpeechField="IncidentType_V" TextAlign="MiddleLeft" WidthPixel="-180"
WidthPercent="50" />
<Label Name="Another TypeContent" Increasable="true"
Width="123" SpeechField="IncidentType_V"
Left="41,42" Top="13"
TextAlign="TopLeft" WidthPixel="-180"
WidthPercent="50"
/>
</foo>
输出:
name,left,width
lblIncidentTypeContent,140,146
"Another TypeContent","41,42",123