具有标题和列映射的CSV实例的多实例XML文件

时间:2017-03-31 12:49:00

标签: xml csv xslt

我正在尝试转换多实例XML文件,其中父节点可以有2个或更多相同类型的子节点。

基本上,我有这种类型的XML文件:

<?xml version='1.0' encoding='UTF-8'?>
<Report_Data>
   <Report_Entry>
      <field1>Record1_field1</field1>
      <field2>Record1_field2</field2>
      <field3>Record1_field3</field3>
      <Report_SubEntry>
         <subField1>Record_1subfield1</subField1>
         <subField2>Record_1subfield2</subField2>
         <subField3>Record_1subfield3</subField3>
      </Report_SubEntry>
      <Report_SubEntry>
         <subField1>Record1_subfield1_subEntry2</subField1>
         <subField2>Record1_subfield2_subEntry2</subField2>
         <subField3>Record1_subfield3_subEntry2</subField3>
      </Report_SubEntry>
   </Report_Entry>
      <Report_Entry>
      <field1>Record2_field1</field1>
      <field2>Record2_field2</field2>
      <field3>Record2_field3</field3>
      <Report_SubEntry>
         <subField1>Record2_subfield1</subField1>
         <subField2>Record2_subfield2</subField2>
         <subField3>Record2_subfield3</subField3>
      </Report_SubEntry>
   </Report_Entry>
 </Report_Data>  

XSLT函数必须可以重复用于类似结构的XML文件,而不必为所有可能的子条目类型硬编码循环或条件。

这是我的XSLT:

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    exclude-result-prefixes="xs this ws">

    <xsl:output method="text" encoding="UTF-8" media-type="text/plain"/>
    <xsl:strip-space elements="*"/>

    <xsl:param name="delimiter" select="'§'" />
    <xsl:param name="quote" select="''" />
    <xsl:param name="break" select="'&#xA;'" />

    <!--
        List of Fields to be included in final CSV.
        !! Use only XPATH node names with prefixes. !!
               If prefixes are to be removed from the header, update the 
    -->

    <xsl:variable name="fieldArray">
        <field>field1</field>
        <field>field2</field>
        <field>field3</field>
        <field>subField1</field>
        <field>subField2</field>
        <field>subField3</field>
    </xsl:variable>



    <xsl:param name="fields" select="document('')/*/xsl:variable[@name='fieldArray']/*" />

    <xsl:template match="//Report_Entry">

        <!-- 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>&#xa;</xsl:text>
        <xsl:apply-templates select="Report_Entry"/>

    </xsl:template>

    <xsl:template match="//Report_Entry">
        <xsl:variable name="currNode" select="." />

        <!-- output the data row -->
        <!-- loop over the field names and find the value of each one in the xml -->

        <xsl:for-each select="$fields">

            <xsl:if test="position() != 1">
                <xsl:value-of select="$delimiter"/>
            </xsl:if>

            <xsl:value-of select="$quote" />

            <xsl:variable name="child" select="$currNode[*]/*/*[name() = current()]" />
            <xsl:variable name="childSecondLevel" select="$currNode[*]/*/*/*[name() = current()]" />
            <xsl:variable name="childThirdLevel" select="$currNode[*]/*/*/*/*[name() = current()]" />

            <xsl:choose>

                <xsl:when test="count($child) > 0">
                    <xsl:value-of select="$child"/>
                </xsl:when>

                <xsl:when test="count($childSecondLevel) > 0">
                    <xsl:value-of select="$childSecondLevel"/>
                </xsl:when>

                <xsl:when test="count($childThirdLevel) > 0">
                    <xsl:value-of select="$childThirdLevel"/>
                </xsl:when>

                <xsl:otherwise>
                    <xsl:value-of select="$currNode/*[name() = current()]" />
                </xsl:otherwise>

            </xsl:choose>

            <xsl:value-of select="$quote" />

        </xsl:for-each>


        <!-- output newline -->
        <xsl:value-of select="$break" />
    </xsl:template>

</xsl:stylesheet>

我得到的输出是:

field1,field2,field3,subField1,subField2,subField3
Record1_field1,Record1_field2,Record1_field3,Record_1subfield1,Record_1subfield2,Record_1subfield3
Record2_field1,Record2_field2,Record2_field3,Record2_subfield1,Record2_subfield2,Record2_subfield3

但我需要的输出是:

field1,field2,field3,subField1,subField2,subField3
Record1_field1,Record1_field2,Record1_field3,Record_1subfield1,Record_1subfield2,Record_1subfield3
Record1_field1,Record1_field2,Record1_field3,Record_1subfield1_subEntry2,Record_1subfield2_subEntry2,Record_1subfield3_subEntry3
Record2_field1,Record2_field2,Record2_field3,Record2_subfield1,Record2_subfield2,Record2_subfield3

有没有人有接近这个的建议?

1 个答案:

答案 0 :(得分:0)

下面怎么样。

我循环遍历Report_SubEntry而不是Report_Entry,这意味着每个Report_SubEntry您将获得一行。

<xsl:template match="/">
    <!-- Output header -->
    <xsl:text>f1,f2,f3,sf1,sf2,sf3&#xa;</xsl:text>

    <!-- Loop through all children of Report_Entry that have childen themselves -->
    <xsl:for-each select="/Report_Data/*/*[*]">
        <xsl:variable name="strCurrentNode" select="name()" />

        <!-- Output parent values -->
        <xsl:for-each select="../*">
            <xsl:if test="name() != $strCurrentNode">
                <xsl:value-of select="." />
                <xsl:text>,</xsl:text>
            </xsl:if>
        </xsl:for-each>

        <!-- Output child values -->
        <xsl:for-each select="./*">
            <xsl:if test="name() != $strCurrentNode">
                <xsl:value-of select="." />

                <xsl:if test="position() != last()">
                    <xsl:text>,</xsl:text>
                </xsl:if>
            </xsl:if>
        </xsl:for-each>

        <!-- output newline -->
        <xsl:text>&#xa;</xsl:text>
    </xsl:for-each>
</xsl:template>
相关问题