如何使用 Perl 将 XML 文件转换为 CSV?

如何使用 Perl 将 XML 文件转换为 CSV?

.asn1我正在寻找一些将(CDR 数据)转换为 CSV 以加载到表中的建议。根据当前的方法,我使用 informatica B2B 解析器将 ASN 文件解析为 XML,而不是使用 XSD 加载到 Greenplum 表。

我希望Perl能够以更好的方式完成这些操作;一天我们收到了大约 30k ASN 文件,这是一个非常大的文件。

用于将 XML 转换为 CSV (对如何在 OS X 上使用 xmlstarlet 将 XML 转换为 CSV 感到困惑?)不确定这种方法是否有效或者 Perl 中是否有任何插件。

ASN 文件是二进制文件,第二步是 XML 到 CSV。

XML 示例:

<?xml version="1.0" encoding="windows-1252"?>
<RadiusCDR_Parent>
<RadiusCDR>
<accountingRequest>
<userName>1200099344</userName>
<nasIPAddress>0A490010</nasIPAddress>
<nasPort>0</nasPort>
<serviceType>2</serviceType>
<framedProtocol>1</framedProtocol>
<framedIPAddress>64702E70</framedIPAddress>
<vendorSpecificExt>
<cisco>
<subAttributeID>1</subAttributeID>
<vendorLength>26</vendorLength>
<data>connect-progress=Call Up</data>
</cisco>
<cisco>
<subAttributeID>1</subAttributeID>
<vendorLength>19</vendorLength>
<data>portbundle=enable</data>
</cisco>
<cisco>
<subAttributeID>250</subAttributeID>
<vendorLength>17</vendorLength>
<data>S10.73.0.17:785</data>
</cisco>
<cisco>
<subAttributeID>253</subAttributeID>
<vendorLength>11</vendorLength>
<data>I0;153521</data>
</cisco>
<cisco>
<subAttributeID>253</subAttributeID>
<vendorLength>11</vendorLength>
<data>O0;559080</data>
</cisco>
</vendorSpecificExt>
<callingStationID>503c.c433.b8df</callingStationID>
<nasIdentifier>INMUNVMBXXXXNB0001AG3WAG001.ril.com</nasIdentifier>
<acctStatusType>3</acctStatusType>
<acctDelayTime>0</acctDelayTime>
<acctInputOctets>0257B1</acctInputOctets>
<acctOutputOctets>0887E8</acctOutputOctets>
<acctSessionID>009B51EC</acctSessionID>
<acctAuthentic>1</acctAuthentic>
<acctSessionTime>2012</acctSessionTime>
<acctInputPackets>1187</acctInputPackets>
<acctOutputPackets>1130</acctOutputPackets>
<eventTimeStamp>140E0A0F 123B0E</eventTimeStamp>
<nasPortType>5</nasPortType>
<nasPortID>0/0/0/902</nasPortID>
</accountingRequest>
</RadiusCDR>
<RadiusCDR_Parent>

我希望除了 Cisco 信息之外,其余所有信息也都是 CSV 格式。

答案1

不要使用XML::Simple.它是馊主意

但从根本上来说,XML 是一种分层数据结构,而 CSV 不是。因此不可能解决一般情况下的翻译问题。

然而,考虑到标准的记录结构,这并不太难:

#!/usr/bin/env perl

use strict;
use warnings;
use XML::Twig;
use Text::CSV;
use Data::Dumper;

my $twig = XML::Twig->new->parse( \*DATA );

#read heading from first record.
my @headings =
    map { $_->tag } $twig->findnodes( '//accountingRequest', 0 )->children;

my $csv_out = Text::CSV->new( { binary => 1, eol => "\n" } );
$csv_out->print( \*STDOUT, \@headings );

foreach my $accountingRequest ( $twig->findnodes('//accountingRequest') ) {
    my @row = map { $accountingRequest->first_child_text($_) } @headings;
    $csv_out->print( \*STDOUT, \@row );
}

这会提取顶级“标签”,然后提取与它们匹配的值,并打印这些值。

但它并不完美,因为如上所述 - 您的数据是分层的。您有cisco记录,您需要决定如何处理这些记录 - 它们应如何在您的 CSV 中表示?

答案2

我得到了下面的代码,用于不同的 XML 文件集和 CSV 文件。

代码:

#!/usr/bin/perl

# Script to illustrate how to parse a simple XML file
# and pick out all the values for a specific element, in
# this case all the titles.

# use strict;
use XML::Simple;
use Data::Dumper;

# create object
$xml = new XML::Simple (KeyAttr=>[]);

# read XML file
$data = $xml->XMLin("test1.xml");


my $booklist = XMLin('test1.xml');    #booklist is the array 
# print Dumper($booklist);

foreach my $FreemanFees (@{$booklist->{FreemanFees}}) {


    print 
    $FreemanFees->{SdcLoanFacilityNumber} , "," , 
    $FreemanFees->{DealId} ,",", 
    $FreemanFees->{Tranche}->{SdcDealNumber} , "," , 
    $FreemanFees->{Tranche}->{ManagerFeeAndCredits}->{ManagerFeeAndCredit}->{FreemanFeesForManager}->{ManagerNumberForFreemanFee}, ",",
    $FreemanFees->{Tranche}->{ManagerFeeAndCredits}->{ManagerFeeAndCredit}->{FreemanFeesForManager}->{currencyId},",",
    $FreemanFees->{Tranche}->{ManagerFeeAndCredits}->{ManagerFeeAndCredit}->{FreemanFeesForManager}->{sdcCurrencyCode} , "," , 
    $FreemanFees->{Tranche}->{ManagerFeeAndCredits}->{ManagerFeeAndCredit}->{FreemanFeesForManager}->{scale}, ",",
    $FreemanFees->{Tranche}->{ManagerFeeAndCredits}->{ManagerFeeAndCredit}->{FreemanFeesForManager}->{content} , "," ,"\n" ;
    }

但是如果我有更多元素,如何获取下一个元素?

相关内容