2009-09-18 83 views
3

我正在嘗試編寫一個awk腳本來將CSV格式的電子表格轉換爲XML格式的Bugzilla錯誤。輸入CSV的格式如下(從XLS電子表格創建並保存爲CSV):如何用awk解析逗號分隔值(csv)?

tag_1,tag_2,...,tag_N 
value1_1,value1_2,...,value1_N 
value2_1,value2_2,...,value2_N 
valueM_1,valueM_2,...,valueM_N 

頭列表示XML標記的名稱。轉換成XML應該如上面的文件如下:

<element> 
    <tag_1>value1_1</tag_1> 
    <tag_2>value1_2</tag_2> 
    ... 
    <tag_N>value1_N</tag_N> 
</element> 
<element> 
    <tag_1>value2_1</tag_1> 
    <tag_2>value2_2</tag_2> 
    ... 
    <tag_N>value2_N</tag_N> 
</element> 
... 

的awk腳本我有做到這一點如下:

BEGIN {OFS = "\n"} 
NR == 1 {for (i = 1; i <=NF; i++) 
      tag[i]=$i 
     print "<bugzilla version=\"3.4.1\" urlbase=\"http://mozilla.com/\" maintainer=\"[email protected]\" exporter=\"[email protected]\">"} 
NR != 1 {print " <bug>" 
     for (i = 1; i <= NF; i++) 
      print "  <" tag[i] ">" $i "</" tag[i] ">" 
     print " </bug>"} 
END {print "</bugzilla>"} 

實際的CSV文件是:

cf_foo,cf_bar,short_desc,cf_zebra,cf_pizza,cf_dumpling ,assigned_to,bug_status,cf_word,cf_caslte 
ABCD,A-BAR-0032,A NICE DESCRIPTION - help me,pretty,Pepperoni,,,NEW,, 

實際輸出是:

$ awk -f csvtobugs.awk bugs.csv

<bugzilla version="3.4.1" urlbase="http://mozilla.com/" maintainer="[email protected]" exporter="[email protected]"> 
    <bug> 
     <cf_foo,cf_bar,short_desc,cf_zebra,cf_pizza,cf_dumpling>ABCD,A-BAR-0032,A</cf_foo,cf_bar,short_desc,cf_zebra,cf_pizza,cf_dumpling> 
     <,assigned_to,bug_status,cf_word,cf_caslte>NICE</,assigned_to,bug_status,cf_word,cf_caslte> 
     <>DESCRIPTION</> 
     <>-</> 
     <>help</> 
     <>me,pretty,Pepperoni,,,NEW,,</> 
    </bug> 
    <bug> 
    </bug> 
</bugzilla> 

顯然,不是預期的結果(我承認,我從這個論壇複製粘貼了這個腳本:http://www.unix.com/shell-programming-scripting/21404-csv-xml.html)。問題在於,從查看awk腳本開始已經過了很長時間,而且我沒有IDEA語法的含義。

回答

4

您需要在BEGIN規則中設置FS = ","以將逗號用作字段分隔符;如果字段分隔符是一個選項卡,這是一種不同的(也是受歡迎的)慣例,即使不使用逗號也常常被稱爲「CSV」的文件中,但您顯示它的代碼應該可以正常工作;-)。

+0

擊敗我兩個,所以我會接受你的! – les2 2009-09-18 17:02:54

+0

你也可以使用'-F'作爲'awk' – 2009-10-31 17:36:03

0

我能夠通過改變FS(字段分隔符)來解決它:

BEGIN { 
    FS=","; 
    OFS = "\n"} 
NR == 1 {for (i = 1; i <=NF; i++) 
      tag[i]=$i 
     print "<bugzilla version=\"3.4.1\" urlbase=\"http://mozilla.com/\" maintainer=\"[email protected]\" exporter=\"[email protected]\">"} 
NR != 1 {print " <bug>" 
     for (i = 1; i <= NF; i++) 
      print "  <" tag[i] ">" $i "</" tag[i] ">" 
     print " </bug>"} 
END {print "</bugzilla>"} 

輸出:

<bugzilla version="3.4.1" urlbase="http://mozilla.com/" maintainer="[email protected]" exporter="[email protected]"> 
    <bug> 
     <cf_foo>ABCD</cf_foo> 
     <cf_bar>A-BAR-0032</cf_bar> 
     <short_desc>A NICE DESCRIPTION - help me</short_desc> 
     <cf_zebra>pretty</cf_zebra> 
     <cf_pizza>Pepperoni</cf_pizza> 
     <cf_dumpling ></cf_dumpling > 
     <assigned_to></assigned_to> 
     <bug_status>NEW</bug_status> 
     <cf_word></cf_word> 
     <cf_caslte></cf_caslte> 
    </bug> 
</bugzilla> 
1

使用的工具,你知道:)

這樣awk腳本看起來沒有處理「和其他CSV奇怪(我認爲它只是分離在選項卡 - 其他答案注意它需要改變分裂,)python,perl .net等有對象來完全處理CSV一個nd XML,可能你可以用awk腳本中的字符數來編寫解決方案,更重要的是可以理解它。

+0

的選項,嘿,它不需要很長時間,是嗎?我已經想出了自己的答案,但只能在第一個答案後2秒(我的答案可以說更好,因爲我包含更多信息):) – les2 2009-09-18 17:22:19

1

請記住,在一個CSV是分裂逗號是罰款,直到你得到以下情形:

1997,Ford,E350,"Super, luxurious truck" 

在這種情況下,它會分裂「超級豪華車」爲兩個項目不正確。我建議在上面的帖子中使用另一種語言的csv庫作爲'標記'狀態。

+0

我通過切換到「TSV」導出來解決此問題(選項卡 - 分離值)。主文件是一個Excel工作表,我不需要一直這樣做。 我正在將基於Excel的跟蹤器(用於'敏捷'方法中'故事')的團隊遷移到Bugzilla。現在每個故事都保存在Bugzilla中。我們使用Eclipse Mylyn插件將故事拉入IDE中作爲任務。 IMO比Excel解決方案好得多。 無論如何,這個初始導入只需要發生一次 - 我不想爲此學習Perl。 AWK腳本工作得很好:) – les2 2009-10-06 15:33:09

0

您可以試試我的csvprintf。它可以將CSV轉換爲XML,然後根據需要使用XSLT進行樣式設置。