我正在尝试从一个包含多个标题行的文件创建一组 xml,每个标题后跟多个详细信息行。
下面是原始 XML 的示例:
编辑:标题表后面的详细信息表数量会有所不同。因此,Sheet[4]/FIELD1 不会总是具有 Header 的值。此外,该文件将始终具有一个或多个标题工作表。工作表是行。
编辑: XSLT-1.0
<Root>
<Sheet>
<FIELD1>Header</FIELD1>
<FIELD2>Value1</FIELD2>
<FIELD3>Value2</FIELD3>
</Sheet>
<Sheet>
<FIELD1>Detail</FIELD1>
<FIELD2>Value3</FIELD2>
<FIELD3>Value4</FIELD3>
</Sheet>
<Sheet>
<FIELD1>Detail</FIELD1>
<FIELD2>Value5</FIELD2>
<FIELD3>Value6</FIELD3>
</Sheet>
<Sheet>
<FIELD1>Header</FIELD1>
<FIELD2>Value7</FIELD2>
<FIELD3>Value8</FIELD3>
</Sheet>
<Sheet>
<FIELD1>Detail</FIELD1>
<FIELD2>Value9</FIELD2>
<FIELD3>Value10</FIELD3>
</Sheet>
<Sheet>
<FIELD1>Detail</FIELD1>
<FIELD2>Value11</FIELD2>
<FIELD3>Value12</FIELD3>
</Sheet>
<Sheet>
<FIELD1>Detail</FIELD1>
<FIELD2>Value13</FIELD2>
<FIELD3>Value14</FIELD3>
</Sheet>
</Root>
以下是输出应类似于以下内容:
编辑:发票的数量将由标题表(行)的数量决定。行项行将与标题后面的明细表数量相同。
<Root>
<Invoice AttribOne="Value1" AttribTwo="Value2" >
<LineItem LIAttribOne="Value3" LIAttribTwo="Value4"/>
<LineItem LIAttribOne="Value5" LIAttribTwo="Value6"/>
</Invoice>
<Invoice AttribOne="Value7" AttribTwo="Value8" >
<LineItem LIAttribOne="Value9" LIAttribTwo="Value10"/>
<LineItem LIAttribOne="Value11" LIAttribTwo="Value12"/>
<LineItem LIAttribOne="Value13" LIAttribTwo="Value14"/>
</Invoice>
</Root>
编辑:回答如下:
试试这个:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="Root">
<xsl:copy>
<Invoice AttribOne="{Sheet[1]/FIELD2}" AttribTwo="{Sheet[1]/FIELD3}">
<xsl:apply-templates select="Sheet[2] | Sheet[3]"/>
</Invoice>
<Invoice AttribOne="{Sheet[4]/FIELD2}" AttribTwo="{Sheet[4]/FIELD3}">
<xsl:apply-templates select="Sheet[5] | Sheet[6] | Sheet[7]"/>
</Invoice>
</xsl:copy>
</xsl:template>
<xsl:template match="Sheet">
<LineItem LIAttribOne="{FIELD2}" LIAttribTwo="{FIELD3}"/>
</xsl:template>
</xsl:stylesheet>
我已经解决了这个问题,并在下面的代码中添加了注释来描述它。
这是解决方案:
<xsl:template match="/Root">
<Root>
<xsl:apply-templates select="Sheet[FIELD1 = 'Header']" />
</Root>
</xsl:template>
<xsl:template match="Sheet[FIELD1 = 'Detail']" >
<LineItem>
<xsl:attribute name="LIAttribOne" >
<xsl:value-of select="FIELD2"/>
</xsl:attribute>
<xsl:attribute name="LIAttribTwo" >
<xsl:value-of select="FIELD3"/>
</xsl:attribute>
</LineItem>
</xsl:template>
<xsl:template match="Sheet[FIELD1 = 'Header']">
<Invoice>
<xsl:attribute name="AttribOne" >
<xsl:value-of select="FIELD2"/>
</xsl:attribute>
<xsl:attribute name="AttribTwo" >
<xsl:value-of select="FIELD3"/>
</xsl:attribute>
<!-- Get the count of all details the previous headers contained -->
<xsl:variable name="prevCnt" select="count(preceding-sibling::*[FIELD1 = 'Detail'])"/>
<!-- Get the count of all details in the previous headers and this header contain -->
<xsl:variable name="newCnt" select="count(following-sibling::*[FIELD1 = 'Header'][1]/preceding-sibling::*[FIELD1 = 'Detail'])"/>
<!-- This will return a 1 if there is a following header, else 0 -->
<xsl:variable name="pos" select="count(following-sibling::*[FIELD1 = 'Header'][1])" />
<!-- select every detail whose position is less than $newCnt - $preCnt or all if there is no following header -->
<xsl:apply-templates select="following-sibling::*[FIELD1 = 'Detail'][position() < ($newCnt - $prevCnt + 1) or $pos = 0]" />
</Invoice>