2013-09-23 132 views
0

我一直在試圖弄清楚如何讓一個XML數據源解析成一個CSV文件,這讓我有點瘋狂。我有一個數據源,我需要解析一個創建CSV。我還需要能夠將節點ID包含在列中。以下是我有:Perl XML到CSV解析

  #!/usr/bin/perl 
      use warnings; 
     use strict; 
     use XML::XPath; 

     #Name of the CSV File 
     my $filename = "parse.csv"; 

     #Create the file. 
     open(INPUT,">$filename") or die "Cannot create file"; 

     #Collect the XML and set nodes 
     my($xp) = XML::XPath->new(join('', <DATA>)); 
     my(@records) = $xp->findnodes('/CATALOG/CD'); 
     my($firstTime) = 0; 

     #Loop through each record 
     foreach my $record (@records) { 
      my(@fields) = $xp->find('./child::*', $record)->get_nodelist(); 
      unless ($firstTime++) { 
      #Print Headers 
       print(join(',', map { $_->getName() } @fields), "\n"); 
      } 
      #Print Content 
       print(join(',', map { $_->string_value() } @fields), "\n"); 
     } 
     #Close the file. 
     close(INPUT); 


     __DATA__ 
     <FOOD> 
      <ITEM id='1'> 
       <Color>Brown</Color> 
       <Name>Steak</Name> 
      </ITEM> 
      <ITEM id='2'> 
       <Color>Blue</Color> 
       <Name>Blueberries</Name> 
      </ITEM> 
      <ITEM id='3'> 
       <Color>Red</Color> 
       <Name>Apple</Name> 
      </ITEM> 
     </FOOD> 

它創建了一個CSV但其空&我想是因爲在foreach循環中的打印線的。

任何幫助將不勝感激!

+0

作爲樣式,不要將文件名硬編碼到腳本中,如果可以避免的話。使它們成爲可選參數,從'<>'(或者做等效)讀取輸入並將輸出寫入到'STDOUT'使得腳本更容易重用,組合和測試。 – reinierpost

回答

2

您正在將標題和內容打印到標準輸出而不是輸出文件。您需要將文件句柄作爲第一個參數傳遞給print而不是它與您要打印的內容之間的逗號。例如:print FILE join(',', ...), "\n";

我也建議不要使用INPUT作爲您要輸出的文件句柄 - 它使理解代碼時有點混亂。

1

鑑於XML架構的簡易性,這更容易做AnyData

例如:

#!/usr/bin/perl 
# This script converts a XML file to CSV format. 

# Load the AnyData XML to CSV conversion modules 
use XML::Parser; 
use XML::Twig; 
use AnyData; 

my $input_xml = "test.xml"; 
my $output_csv = "test.csv"; 


$flags->{record_tag} = 'ITEM'; 
adConvert('XML', $input_xml, 'CSV', $output_csv, $flags); 

請問你的數據結構(XML)轉換成:

id,Color,Name 
1,Brown,Steak 
2,Blue,Blueberries 
3,Red,Apple 
1

就你而言,你正在使用/ CATALOG/CD而不是你的數據。請使用類似

my(@records) = $xp->findnodes('/FOOD/ITEM'); 
.... 
... 
... 
print INPUT (join(',', map { $_->getName() } @fields), "\n");