使用XSLT模板遍历嵌套的XML结构

时间:2015-04-14 12:10:34

标签: xml csv xslt

我是XSLT的新手。我已经在这个论坛中查看了不同的解决方案,但我的问题有点不同。假设我们有一个xml:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Transaction>
    <operation>DEBIT</operation>
    <autoRegistration>true</autoRegistration>
    <allowRecurrence>true</allowRecurrence>
    <network>VISA</network>
    <source>RANDOM</source>
    <origin>
        <merchant>ABC</merchant>
        <transactionId>1234</transactionId>
        <channel>SINGLE</channel>
        <country>DE</country>
    </origin>
    <customer>
        <number>338317</number>
        <eMail>someone@somewhere.de</eMail>
        <dateOfBirth>1975-06-15</dateOfBirth>
        <contact>
            <eMail>someone@somewhere.de</eMail>
            <phoneNumbers></phoneNumbers>
        </contact>
        <clientInfo>
            <ip>123.111.123.123</ip>
            <userAgent>Mozilla/5.0 (Windows NT 6.2; WOW64)</userAgent>
            <acceptHeader>*/*</acceptHeader>
        </clientInfo>
    </customer>
</Transaction>

假设我需要使用XSLT将其转换为CSV。我需要我的CSV如下:

operation,allowRecurrence,source,merchant
DEBIT,true,RANDOM,ABC

现实世界的问题更复杂,嵌套的xml元素更多。我应该如何为这样的问题设计我的XSLT,以便它处理多层嵌套XML元素并为我准备一个CSV。 到目前为止,我已经成功地组成了一起:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text"/>

    <xsl:variable name="delimiter" select="','"/>

    <!-- define an array containing the fields we are interested in -->
    <xsl:variable name="fieldArray">
        <field>operation</field>
        <field>allowRecurrence</field>
        <field>source</field>
        <field>merchant</field>
    </xsl:variable>
    <xsl:param name="fields" select="document('')/*/xsl:variable[@name='fieldArray']/*"/>

    <xsl:template match="/">
        <xsl:variable name="currNode" select="."/>
        <!-- output the header row -->
        <xsl:for-each select="$fields">
            <xsl:if test="position() != 1">
                <xsl:value-of select="$delimiter"/>
            </xsl:if>
            <xsl:value-of select="."/>
        </xsl:for-each>

        <!-- output newline -->
    <xsl:text>
</xsl:text>
        <xsl:for-each select="$fields" >
            <xsl:if test="position() != 1">
                <xsl:value-of select="$delimiter"/>
            </xsl:if>
            <xsl:value-of select="$currNode/*/*[name() = current()]"/>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

我陷入逻辑<xsl:value-of select="$currNode/*/*[name() = current()]"/> ...如何在此循环中改变XML元素嵌套的级别。

1 个答案:

答案 0 :(得分:1)

XML文档不是&#34;任意的&#34 ;;他们遵循预定义的架构。您最好的策略是将XSLT定制为预期的架构。在您的示例中,这意味着:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>

<xsl:template match="/Transaction">
    <xsl:text>operation,allowRecurrence,source,merchant,eMail&#10;</xsl:text>
    <xsl:value-of select="operation"/>
    <xsl:text>,</xsl:text>
    <xsl:value-of select="allowRecurrence"/>
    <xsl:text>,</xsl:text>
    <xsl:value-of select="source"/>
    <xsl:text>,</xsl:text>
    <xsl:value-of select="origin/merchant"/>
    <xsl:text>,</xsl:text>
    <xsl:value-of select="customer/eMail"/>
</xsl:template>

</xsl:stylesheet>

您想要遍历文档,寻找名为&#39; xyx&#39;的节点。当有多个具有相同名称的节点时会失败。例如,您的XML有两个eMail个节点,您的方法永远不会到达customer/contact/eMail的那个节点。