使用XSLT从XML编写数据的列与行中的行

我试图采取下面的XML结构(清理所以请原谅任何不一致),并通过XSLT 1.0转换为每个通道两列,一个开始时间和一个显示标题的分组列。 XML看起来像:

<days> <DAY> <channel> <CHANNEL name="A"/> </channel> <transmissions> <TRANSMISSION title="Show 1"> <starttime> <TIME hours="6" minutes="00" seconds="00" timeinseconds="21600"/> </starttime> </TRANSMISSION> <TRANSMISSION title="Show 2"> <starttime> <TIME hours="7" minutes="45" seconds="00" timeinseconds="27900"/> </starttime> </TRANSMISSION> <TRANSMISSION title="Show 3"> <starttime> <TIME hours="8" minutes="00" seconds="00" timeinseconds="28800"/> </starttime> </TRANSMISSION> </transmissions> <date> <DATE year="2015" month="3" day="2" dayname="Monday" monthname="March" dateindays="41698"/> </date> </DAY> <DAY> <channel> <CHANNEL name="B"/> </channel> <transmissions> <TRANSMISSION title="Show 1"> <starttime> <TIME hours="6" minutes="00" seconds="00" timeinseconds="21600"/> </starttime> </TRANSMISSION> <TRANSMISSION title="Show 4"> <starttime> <TIME hours="7" minutes="45" seconds="00" timeinseconds="27900"/> </starttime> </TRANSMISSION> <TRANSMISSION title="Show 2"> <starttime> <TIME hours="8" minutes="00" seconds="00" timeinseconds="28800"/> </starttime> </TRANSMISSION> </transmissions> <date> <DATE year="2015" month="3" day="2" dayname="Monday" monthname="March" dateindays="41698"/> </date> </DAY> </days> 

从这段代码我需要创build一个Excel文档,每个通道有两列,一列是开始时间,另一列是传输的标题。 这些需要并肩(我会发布一个图像,但我没有足够的声誉)。

我试图build立一个for-each对传输,但当然,这意味着第二个通道被忽略,直到第一个通道传输完成,这创build数据在第2行的通道A和第3行的通道B,而不是数据在两个频道中排在第二位。

 <xsl:for-each select="DAY/transmissions/TRANSMISSION"> <xsl:sort select="starttime/TIME/@durationinseconds" data-type="number" order="ascending"/> <Row ss:AutoFitHeight="0" ss:Height="29.25"> <xsl:if test="../../channel/CHANNEL/@name = 'A'"> <xsl:variable name="time"> <xsl:value-of select="starttime/TIME/@timeinseconds"/> </xsl:variable> <Cell> <Data ss:Type="String"> <xsl:apply-templates select="starttime/TIME" mode="time"/> </Data> </Cell> <Cell ss:StyleID="s17"> <Data ss:Type="String"> <xsl:apply-templates select="../TRANSMISSION[starttime/TIME/@timeinseconds = $time]"/> </Data> </Cell> </xsl:if> <xsl:if test="../../channel/CHANNEL/@name = 'B'"> (repeat of above) 

我意识到这个代码有多个问题,但是核心问题是我在处理这个代码中的其他小问题之前要解决的问题。

实际上,我需要写一个列而不是一行,但这当然是不可能的。 我怎样才能让数据显示为两组数据,其中每个频道都有一个开始时间列表和关联的节目标题?

我已经考虑创build一个“主”表,然后使用引用公式来获取信息,但是整个报表所需的每个通道的数据量和数据的可变性会造成如何构build“子”表单的问题。 更不用说最终用户不喜欢这个解决scheme。

我也尝试过在DAY节点上build立for-each,但是在切换到通道B之前,通过构build整个通道A的数据来加剧这个问题。

这个样式表可能是你正在尝试做的一个起点:

XSLT 1.0

 <!-- (I needed a starting point, you will probably have something different) --> <xsl:template match="/"> <wrapperElement> <!-- create the rows --> <xsl:apply-templates select="//DAY[1]//TRANSMISSION" mode="createRow"/> </wrapperElement> </xsl:template> <!-- template to create the row --> <xsl:template match="TRANSMISSION" mode="createRow"> <Row ss:AutoFitHeight="0" ss:Height="29.25"> <xsl:apply-templates select="." mode="createCells"/> </Row> </xsl:template> <!-- template to create two cells for each channel --> <xsl:template match="TRANSMISSION" mode="createCells"> <Cell> <Data ss:Type="String"> <xsl:apply-templates select="starttime/TIME" mode="time"/> </Data> </Cell> <Cell ss:StyleID="s17"> <Data ss:Type="String"> <xsl:apply-templates select="@title"/> </Data> </Cell> <!-- cells for next channel --> <xsl:apply-templates select="ancestor::DAY/following-sibling::DAY[1]//TRANSMISSION[count(preceding-sibling::TRANSMISSION) = count(current()/preceding-sibling::TRANSMISSION)]" mode="createCells"/> </xsl:template> 

值得注意的几点:

  • 第一个通道的每个TRANSMISSION元素相匹配,以创build一个Row
  • 相同的元素由另一个模板(以不同的mode )处理,以产生具有时间和标题的两个Cell
  • 那么处理具有相同位置的下一个通道的TRANSMISSION元素以创build同一Row中的其他Cell