使用 XSLT 将 CSV 文件转换为 XML

Posted

技术标签:

【中文标题】使用 XSLT 将 CSV 文件转换为 XML【英文标题】:Convert CSV file to XML using XSLT 【发布时间】:2019-12-15 23:46:02 【问题描述】:

我有需要转换为 XML 的 CSV 文件,但问题是,我只需要某些字段并且行数会发生变化。

我是 XSLT 的新手,不知道如何将此 CSV 转换为 XML,尤其是因为 CSV 文件具有不同的行数/行数。

Pastebin 问题链接:https://pastebin.com/AfRxRRJX

例如:

示例输入数据如下所示:

1,12345,7654321,1,08/08/19,08/08/19
2,12345,12345678,3
2,12345,22345679,7
2,12345,32345680,6
2,12345,42345681,2
3,12345,

从人类角度看数据是什么样子的:

First line, ID, accountNo, ???, orderDate, orderDate
Product row, ID, productCode, quantity
Product row, ID, productCode, quantity
Product row, ID, productCode, quantity
Product row, ID, productCode, quantity
Last Line, ID,

输出应该是这样的:

<?xml version="1.0"?>
<orders>
    <order accountNo="7654321" orderDate="08/08/19">
        <orderItems>
            <orderItem productCode="12345678" quantity="3"/>
            <orderItem productCode="22345679" quantity="7"/>
            <orderItem productCode="32345680" quantity="6"/>
            <orderItem productCode="42345681" quantity="2"/>
        </orderItems>
    </order>
</orders>

我尝试将 XSLT 代码的不同 sn-ps 放在一起,但转换后总是显示为垃圾。

================================================ ===================================

我做到了,但不幸的是,我需要先将 CSV 转换为 XML,然后再将 XML 转换为 XML 格式! '

<xsl:param name="csv-encoding" as="xs:string" select="'utf-8'"/>
<xsl:param name="csv-uri" as="xs:string" select="'file:///D:/csv%20to%20xml/example1.dat'"/>

<xsl:template match="/" name="csv2xml">
    <orders>
        <xsl:choose>
            <xsl:when test="unparsed-text-available($csv-uri, $csv-encoding)">
                <order>
                 <xsl:variable name="csv" select="unparsed-text($csv-uri, $csv-encoding)" />
                 <xsl:variable name="order-info" as="xs:string*">
                     <xsl:analyze-string select="$csv" regex="\r\n?|\n">
                         <xsl:non-matching-substring>
                             <xsl:if test="starts-with(., '1')">
                                 <xsl:copy-of select="tokenize(.,',')"/>
                             </xsl:if>
                         </xsl:non-matching-substring>
                     </xsl:analyze-string>
                 </xsl:variable>
                 <xsl:attribute name="accountNo">
                     <xsl:value-of select="$order-info[3]"/>
                 </xsl:attribute>
                <xsl:attribute name="orderDate">
                    <xsl:value-of select="$order-info[5]"/>
                </xsl:attribute>
                 <orderItems>
                     <xsl:analyze-string select="$csv" regex="\r\n?|\n">
                         <xsl:non-matching-substring>
                             <xsl:if test="starts-with(., '2')">
                                 <orderItem>
                                     <xsl:for-each select="tokenize(.,',')">
                                         <xsl:variable name="pos" select="position()"/>
                                         <xsl:if test="$pos=3">
                                             <xsl:attribute name="productCode">
                                                 <xsl:value-of select="."/>
                                             </xsl:attribute>    
                                         </xsl:if>
                                         <xsl:if test="$pos=4">
                                             <xsl:attribute name="quantity">
                                                 <xsl:value-of select="."/>
                                             </xsl:attribute>    
                                         </xsl:if>
                                     </xsl:for-each>
                                 </orderItem>
                             </xsl:if>
                         </xsl:non-matching-substring>
                     </xsl:analyze-string>
                 </orderItems>
                </order>
            </xsl:when>
            <xsl:otherwise>
                <test>
                </test>
            </xsl:otherwise>
        </xsl:choose>
    </orders>
</xsl:template>

'

【问题讨论】:

出了什么问题,因为你想要的和结果 xml 看起来一样。 我会在明天晚上尝试,我会在这里发布代码以寻求帮助。非常感谢! 这将是一项非常容易或稍微复杂一点的任务,具体取决于您所针对的 XSLT 版本和输入的大小。这是因为在 XSLT 1.0 中,字符串处理必须通过递归来完成,并且为了避免大输入源上的堆栈溢出,拆分任务可能会很棘手。在 XSLT 2+ 中,您有 xsl:analyze-string 正则表达式指令。 我做到了,但不幸的是,我需要先将 CSV 转换为 XML,然后再将 XML 转换为 XML 格式! 【参考方案1】:

你不能做简单的事情吗:

<xsl:template match="/">
    <xsl:variable name="lines" select="tokenize($csv, '&#10;')" />
    <orders>
        <xsl:variable name="line1-fields" select="tokenize($lines[1], ',')" />
        <order accountNo="$line1-fields[3]" orderDate="$line1-fields[5]">
            <orderItems>
                <xsl:for-each select="$lines[not(position() = (1, last()))]">
                    <xsl:variable name="fields" select="tokenize(., ',')" />
                    <orderItem productCode="$fields[3]" quantity="$fields[4]"/>
                </xsl:for-each>
            </orderItems>
        </order>
    </orders>
</xsl:template>

【讨论】:

以上是关于使用 XSLT 将 CSV 文件转换为 XML的主要内容,如果未能解决你的问题,请参考以下文章

使用 Python 或 XSLT 将复杂的 XML 转换为 CSV

使用 XSLT 将 XML 转换为 CSV

使用XSLT将XML转换为csv

使用 XSLT 将 XML 转换为多个 CSV

如何编写 XSLT 将 XML 转换为 CSV?

SSIS - XML 任务未使用我创建的 XSLT-2.0 转换我的 XML 文件