需要使用for循环处理文件
我写了下面的代码将csv转换为xml。这里为每一列写了单独的标签 在输入文件中有1到278列。在输出文件中需要有从A1到A278的标记,
代码:
file_in="Prepaid_plan_voucher.csv"
file_out="Prepaid_plan_voucher.xml"
echo '<?xml version="1.0"?>' > $file_out
#echo '<Customers>' >> $file_out
echo ' <TariffRecords>' >> $file_out
echo ' <Tariff>' >> $file_out
while IFS=$',' read -r -a arry
do
# echo ' <TariffRecords>' >> $file_out
# echo ' <Tariff>' >> $file_out
echo ' <A1>'${arry[0]}'</A1>' >> $file_out
echo ' <A2>'${arry[1]}'</A2>' >> $file_out
echo ' <A3>'${arry[2]}'</A3>' >> $file_out
# echo ' </TariffRecords>' >> $file_out
# echo ' </Tariff>' >> $file_out
done < $file_in
#echo '</Customers>' >> $file_out
echo ' <TariffRecords>' >> $file_out
echo ' <Tariff>' >> $file_out
示例输入文件。(这是实际输入文件中的示例记录,将包含278列)。 如果输入文件有两个或三个记录,则需要在一个XML文件中附加相同的记录。
name,Tariff Summary,Record ID No.,Operator Name,Circle (Service Area),list
Prepaid Plan Voucher,test_All calls 2p/s,TT07PMPV0188,Ta Te,Gu,
Prepaid Plan Voucher,test_All calls 3p/s,TT07PMPV0189,Ta Te,HR,
示例输出文件 以上两个关税记录,关税将在xml文件的开头和结尾进行硬编码。
<TariffRecords>
<Tariff>
<A1>Prepaid Plan Voucher</A1>
<A2>test_All calls 2p/s</A2>
<A3>TT07PMPV0188</A3>
<A4>Ta Te</A4>
<A5>Gu</A5>
<A6></A6>
<Tariff>
<Tariff>
<A1>Prepaid Plan Voucher</A1>
<A2>test_All calls 3p/s</A2>
<A3>TT07PMPV0189</A3>
<A4>Ta Te</A4>
<A5>HR</A5>
<A6></A6>
<Tariff>
<TariffRecords>
答案 0 :(得分:2)
尽管如此,这不是最优雅的解决方案,但我认为如果我理解正确的话,你只想这样做。因此,尽可能多地修改代码:
NUM_OF_COLS=5
echo '<TariffRecords>' >> $file_out
while IFS=$',' read -r -a arry
do
tariff=" <Tariff>\n"
for i in $(seq 0 $NUM_OF_COLS); do
tariff="${tariff} <A$i>${arry[$i]}</A$i>\n"
done
tariff="${tariff} </Tariff>"
echo -e ${tariff} >> $file_out
done < <(tail -n +1 $file_in)
echo '</TariffRecords>' >> $file_out
需要注意的事项:
我们正在通过以下方式跳过CSV标题:
<(tail -n +1 $file_in)
在0
到$NUM_OF_COLS
范围内生成“foeach”循环,代表列的索引:
$(seq 0 $NUM_OF_COLS)
追加字符串:
tariff="${tariff}......"
使用
echo -e ...
为了保留新的行和良好的格式,但您可以使用其他bash实用程序,例如xmllint
,以便进行相当格式化。
编辑:适用于多个文件
要处理多个文件,请替换硬编码:
file_in="Prepaid_plan_voucher.csv"
file_out="Prepaid_plan_voucher.xml"
通过
file_in="$1" # Take the name as an argument from command line
file_out="${1%.csv}.xml" # Remove csv suffix and append xml
并从命令行为每个csv
文件运行脚本,例如像这样:
$ for f in $(ls *.csv); do ./ourscript.sh $f; done
答案 1 :(得分:1)
由于在注释中已提及它,因此这里是使用XSLT 3.0的选项。
我测试过的处理器为Saxon-HE 9.8,并通过Java命令行运行。应该很容易将其合并到Shell脚本中以处理多个文件。
CSV输入(添加了额外的一行以显示对另一个空条目和带引号的条目的处理,这些条目包含不是分隔符的逗号)
name,Tariff Summary,Record ID No.,Operator Name,Circle (Service Area),list
Prepaid Plan Voucher,test_All calls 2p/s,TT07PMPV0188,Ta Te,Gu,
Prepaid Plan Voucher,test_All calls 3p/s,TT07PMPV0189,Ta Te,HR,
Prepaid Plan Voucher,,TT07PMPV0190,Ta Te,DH,"some,comma,separated,list"
XSLT 3.0
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" expand-text="yes">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="csv-uri"/>
<xsl:param name="csv-encoding" select="'UTF-8'"/>
<xsl:template name="init">
<TariffRecords>
<xsl:choose>
<xsl:when test="unparsed-text-available($csv-uri, $csv-encoding)">
<xsl:call-template name="csv2xml"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="error">
<xsl:text>Error reading "{$csv-uri}" (encoding "{$csv-encoding}").</xsl:text>
</xsl:variable>
<xsl:message><xsl:value-of select="$error"/></xsl:message>
</xsl:otherwise>
</xsl:choose>
</TariffRecords>
</xsl:template>
<xsl:template name="csv2xml">
<xsl:variable name="csv_content" select="unparsed-text($csv-uri, $csv-encoding)"/>
<xsl:analyze-string select="$csv_content" regex="\r?\n">
<xsl:non-matching-substring>
<xsl:if test="position() > 1"><!--ignore header-->
<Tariff>
<xsl:analyze-string select="concat(.,',')" regex='"([^"]*)",?|([^,]+),?'>
<!--group 1 is wrapped in quotes-->
<!--group 2 is not wrapped quotes-->
<xsl:matching-substring>
<xsl:element name="A{position()}">
<xsl:value-of select="(regex-group(1),regex-group(2))" separator=""/>
</xsl:element>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:element name="A{position()}"/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</Tariff>
</xsl:if>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
</xsl:stylesheet>
命令行(see here,以获取有关从命令行运行Saxon的更多信息)
java -cp "C:/apps/SaxonHE9-8-0-11J/saxon9he.jar" net.sf.saxon.Transform -it:init -xsl:"csv2xml.xsl" -o:"output.xml" csv-uri="input.csv"
输出
<?xml version="1.0" encoding="UTF-8"?>
<TariffRecords>
<Tariff>
<A1>Prepaid Plan Voucher</A1>
<A2>test_All calls 2p/s</A2>
<A3>TT07PMPV0188</A3>
<A4>Ta Te</A4>
<A5>Gu</A5>
<A6/>
</Tariff>
<Tariff>
<A1>Prepaid Plan Voucher</A1>
<A2>test_All calls 3p/s</A2>
<A3>TT07PMPV0189</A3>
<A4>Ta Te</A4>
<A5>HR</A5>
<A6/>
</Tariff>
<Tariff>
<A1>Prepaid Plan Voucher</A1>
<A2/>
<A3>TT07PMPV0190</A3>
<A4>Ta Te</A4>
<A5>DH</A5>
<A6>some,comma,separated,list</A6>
</Tariff>
</TariffRecords>