我正在尝试转换多实例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="'
'" />
<!--
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>
</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
有没有人有接近这个的建议?
答案 0 :(得分:0)
下面怎么样。
我循环遍历Report_SubEntry
而不是Report_Entry
,这意味着每个Report_SubEntry
您将获得一行。
<xsl:template match="/">
<!-- Output header -->
<xsl:text>f1,f2,f3,sf1,sf2,sf3
</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>
</xsl:text>
</xsl:for-each>
</xsl:template>