我正在尝试在Perl中解析CSV文件,并将某些列的信息粘贴到XML文件中。我从未在Perl中做过任何事情,我的想法是将数据存储到数组中,然后在构建数据时将信息从数组中拉出来。
我确定我做错了几件事,因为我没有得到我期望的值,而是看起来像内存中的数组地址(这是一个例子:ARRAY(0x35e9360)
。< / p>
有人可以帮助我并指出一个更好的解决方案吗?
以下是相关代码:
use Text::CSV;
use utf8;
use XML::Simple qw(XMLout);
use XML::Twig;
use File::Slurp;
use Encode;
&buildXML();
my $csv = Text::CSV->new( { binary => 1 } ) # should set binary attribute.
or die "Cannot use CSV: " . Text::CSV->error_diag();
$csv = Text::CSV->new( { sep_char => '|' } );
$csv = Text::CSV_XS->new( { allow_loose_quotes => 1 } );
my $t = XML::Twig->new( pretty_print => indented );
$t->parsefile('output.xml');
$out_file = "output.xml";
open( my $fh_out, '>>', $out_file ) or die "unable to open $out_file for writing: $!";
my $root = $t->root; #get the root
open my $fh, "<:encoding(utf8)", "b.txt" or die "text.txt: $!";
while ( my $row = $csv->getline($fh) ) {
my @rows = $row;
$builds = $root->first_child(); # get the builds node
$xcr = $builds->first_child(); #get the xcr node
my $xcrCopy = $xcr->copy(); #copy the xcr node
$xcrCopy->paste( after, $xcr ); #paste the xcr node
$xcr->set_att( id => "@rows[0]" );
print {$fh_out} $t->sprint();
}
$csv->eof or $csv->error_diag();
这是一个测试文件:
ID|Name|Pos
1|a|265
2|b|950
3|c|23
4|d|798
5|e|826
6|f|935
7|g|852
8|h|236
9|i|642
这是由buildXML()
sub构建的XML。
<?xml version='1.0' standalone='yes'?>
<project>
<builds>
<xcr id="" name="" pos="" />
</builds>
</project>
答案 0 :(得分:3)
此程序似乎按您的要求执行
链接:
在对代码进行逆向工程以发现您的目标之后,我发现它确实是一个相当简单的问题。如果你在CSV文件中为每一行添加一个新的xcr
元素来解释你的意图,并且属性对应于列
您可能根本不需要XML模板文件,或者只是具有空属性的模板xcr
元素是多余的?我也想知道你是否想跳过CSV文件中的标题行?这些更改很简单,但我已将代码保留在最简单的状态
use utf8;
use strict;
use warnings 'all';
use autodie;
use Text::CSV;
use XML::Twig;
use Encode;
use constant XML_FILE => 'output.xml';
use constant CSV_FILE => 'b.txt';
build_xml(XML_FILE);
my $csv = Text::CSV->new( {
sep_char => '|',
binary => 1,
allow_loose_quotes => 1, # This is brought forward. Probably unnecessary
} );
my $t = XML::Twig->new(
pretty_print => 'indented',
);
$t->parsefile(XML_FILE);
my ($xcr) = $t->findnodes('/project/builds/xcr');
open my $fh, '<:encoding(utf8)', CSV_FILE;
while ( my $row = $csv->getline($fh) ) {
my ($id, $name, $pos) = @$row;
my $xcr_copy = $xcr->copy;
$xcr_copy->set_att( id => $id, name => $name, pos => $pos );
$xcr_copy->paste( last_child => $xcr->parent );
}
$t->print;
sub build_xml {
open my $fh, '>', shift;
print $fh <<__END_XML__;
<?xml version='1.0' standalone='yes'?>
<project>
<builds>
<xcr id="" name="" pos="" />
</builds>
</project>
__END_XML__
}
<?xml version="1.0" standalone="yes"?>
<project>
<builds>
<xcr id="" name="" pos=""/>
<xcr id="ID" name="Name" pos="Pos"/>
<xcr id="1" name="a" pos="265"/>
<xcr id="2" name="b" pos="950"/>
<xcr id="3" name="c" pos="23"/>
<xcr id="4" name="d" pos="798"/>
<xcr id="5" name="e" pos="826"/>
<xcr id="6" name="f" pos="935"/>
<xcr id="7" name="g" pos="852"/>
<xcr id="8" name="h" pos="236"/>
<xcr id="9" name="i" pos="642"/>
</builds>
</project>
阅读完评论后(这样的内容应编辑成问题)说&#34;我正在从头开始构建[XML数据]。有一个sub buildXML&#34; 我认为这更有可能是你需要的。使用XML::Twig
,最简单的方法是解析一些XML文本,而不是创建和链接单个XML::Twig::Elt
对象
$t
对象首先没有xcr
个对象。它们都是通过XML::Twig::Elt->new
创建的,并粘贴为last_child
元素的builds
require v5.14.1; # For autodie
use utf8;
use strict;
use warnings 'all';
use autodie;
use Text::CSV;
use XML::Twig;
use Encode;
use constant XML_FILE => 'output.xml';
use constant CSV_FILE => 'b.txt';
my $t = XML::Twig->new(
pretty_print => 'indented',
);
$t->parse(<<END_XML);
<project>
<builds/>
</project>
END_XML
my ($builds) = $t->findnodes('/project/builds');
my $csv = Text::CSV->new( {
sep_char => '|',
binary => 1,
allow_loose_quotes => 1,
} );
{
open my $fh, '<:encoding(utf8)', CSV_FILE;
<$fh>; # Drop the header line
while ( my $row = $csv->getline($fh) ) {
my ($id, $name, $pos) = @$row;
my $xcr = XML::Twig::Elt->new(xcr => {
id => $id,
name => $name,
pos => $pos
});
$xcr->paste( last_child => $builds );
}
}
open my $fh, '>encoding(utf-8)', XML_FILE;
$t->set_output_encoding('UTF-8');
$t->print($fh, 'indented');
<?xml version="1.0" encoding="UTF-8"?><project>
<builds>
<xcr id="1" name="a" pos="265"/>
<xcr id="2" name="b" pos="950"/>
<xcr id="3" name="c" pos="23"/>
<xcr id="4" name="d" pos="798"/>
<xcr id="5" name="e" pos="826"/>
<xcr id="6" name="f" pos="935"/>
<xcr id="7" name="g" pos="852"/>
<xcr id="8" name="h" pos="236"/>
<xcr id="9" name="i" pos="642"/>
</builds>
</project>
答案 1 :(得分:1)
Text::CSV
的{{3}}方法返回一个arrayref
它使用$ io-&gt; getline()从IO对象$ io中读取一行,并将此行解析为数组引用。
ARRAY(0x35e9360)
确实是打印出数组引用时得到的。通常,许多解析器通常返回对行的数组的引用。因此,您需要取消引用,通常是@{$arrayref}
,但在这种情况下,没有歧义,可以删除curles,@$arrayref
。
use warnings;
use strict;
use Text::CSV_XS;
use XML::Twig;
my $csv = Text::CSV_XS->new (
{ binary => 1, sep_char => '|', allow_loose_quotes => 1 }
) or die "Cannot use CSV: " . Text::CSV->error_diag();
my $t = XML::Twig->new(pretty_print => 'indented');
$t->parsefile('output.xml');
my $out_file = 'output.xml';
open my $fh_out, '>>', $out_file or die "Can't open $out_file for append: $!";
my $root = $t->root;
my $file = 'b.txt';
open my $fh, "<:encoding(UTF-8)", $file or die "Can't open $file: $!";
while (my $rowref = $csv->getline($fh)) {
#my @cols = @$rowref;
#print "@cols\n";
my $builds = $root->first_child(); # get the builds node
my $xcr = $builds->first_child(); # get the xcr node
my $xcrCopy = $xcr->copy(); # copy the xcr node
$xcrCopy->paste('after', $xcr); # paste the xcr node
$xcr->set_att(id => $rowref->[0]); # or $cols[0];
print $fh_out $t->sprint();
}
为CSV文件打印(当@cols
及其打印未被注释时)
ID Name Pos 1 a 265 2 b 950 ...
所以我们已经读好了文件。
从问题中复制XML处理,但使用CSV值的部分除外。我们取当前行的第一个元素,$rowref->[0]
,因为$rowref
是一个引用。 (或者使用取消引用数组中的元素$cols[0]
。)
我不知道预期的输出是什么,但它是从模板构建的,对于此代码似乎没问题。
请注意。数组的单个元素是标量,因此它带有$
- 所以,
$cols[0]
。如果要提取多个列,可以使用数组切片,在这种情况下,结果是一个数组,因此它需要@
,例如@cols[0,2]
是一个数组,第一和第三个要素。然后可以将其分配给列表,例如my ($c1, $c3) = @cols[0,2];
。