Perl

如何使用 Perl 將 XML 文件轉換為 CSV?

  • December 20, 2015

我正在尋找一些將.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 中。

不要使用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 中表示?

引用自:https://unix.stackexchange.com/questions/168112