
Estou procurando alguma sugestão para converter .asn1
(dados CDR) em CSV para carregar em tabelas. De acordo com a abordagem atual, estou usando o analisador B2B da Informatica para analisar o arquivo ASN para XML, em vez de usar o carregamento XSD para tabelas Greenplum.
Espero que Perl possa fazer essas operações de uma maneira melhor; por um dia estamos recebendo um arquivo ASN de aproximadamente 30k, que é um arquivo muito grande.
Para converter XML em CSV (Ficou confuso sobre como converter XML em CSV usando xmlstarlet no OS X?) não tenho certeza se essa abordagem funciona ou se existe algum plugin em Perl.
Os arquivos ASN são arquivos binários, a segunda etapa é XML para CSV.
Exemplo de 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>
Eu gostaria que, além das informações da Cisco, todas as informações também estivessem em CSV.
Responder1
Não use XML::Simple
. É umpéssima ideia.
Mas fundamentalmente - XML é uma estrutura de dados hierárquica, CSV não. Como resultado, é impossível resolver uma tradução para o caso geral.
No entanto, dada uma estrutura de registro padrão, não é muito difícil:
#!/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 );
}
Isso extrai a 'tag' de nível superior e, em seguida, os valores que correspondem a eles e os imprime.
Porém, não é perfeito, porque, como foi dito, seus dados são hierárquicos. Você tem cisco
registros e precisa decidir o que deseja fazer com eles - como eles devem ser representados em seu CSV?
Responder2
Peguei o código abaixo, para diferentes conjuntos de arquivos XML para CSV.
Código:
#!/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" ;
}
Mas como buscar os próximos elementos se eu tiver mais?