我有以下XML(它是简化的,省略了大多数属性):
<Document>
<Transfer Name="" From="" To=""/>
<Transfer Name="" From="" To=""/>
<OtherElement/>
<OtherElement/>
<Flight AirLina="" From="" To=""/>
<Flight AirLina="" From="" To=""/>
<OtherElement/>
<Hotel Name="" Duration=""/>
<Hotel Name="" Duration=""/>
<OtherElement/>
<OtherElement/>
<Extras Name="" Price=""/>
<Extras Name="" Price=""/>
<Extras Name="" Price=""/>
<Extras Name="" Price=""/>
<Extras Name="" Price=""/>
<Extras Name="" Price=""/>
<OtherElement/>
<OtherElement/>
</Document>
我有一个变量,包含不同的元素:
<xsl:variable name="packageElements"
select="/Document/Transfer | /Document/Coach | /Document/Flight | /Document/Hotel | /Document/Extras" />
我想在包含2列的表中显示该数据。我正在使用XSLT1.0和MSXSL处理器。
我一直在尝试用我能想到的最简单的解决方案:
<table>
<tbody>
<xsl:for-each select="$packageElements[position() mod 2 = 1]">
<tr>
<td>
<!-- current element -->
<xsl:value-of select="local-name()"/>
</td>
<td>
<!-- element following the current in the $packageElements variable -->
<!-- Here is where I'm stuck, I can't figure out how to correctly pick it up :( -->
</td>
</tr>
</xsl:for-each>
</tbody>
</table>
非常感谢任何帮助。
答案 0 :(得分:1)
我认为复杂性就在这里:
元素跟在$ packageElements变量中的当前
之后
这是$ packageElements节点集中的一个节点,其position()大于当前节点。但是,$ packegeElements node-set 中当前节点的位置是什么?
检查this。 Dimitre构建一个表达式,它是当前节点的先前节点(在文档中)与节点集之间的交集计数。
答案 1 :(得分:1)
此转化:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vData" select="/*/*"/>
<xsl:template match="/">
<table border="1">
<xsl:apply-templates select="$vData[position() mod 2 = 1]"/>
</table>
</xsl:template>
<xsl:template match="nums/*">
<xsl:variable name="vPos" select="position()"/>
<tr>
<td><xsl:value-of select="name()"/></td>
<td><xsl:value-of select="$vData[position() = 2*$vPos]"/></td>
</tr>
</xsl:template>
</xsl:stylesheet>
应用于此XML文档时:
<nums>
<A>01</A>
<num>02</num>
<B>03</B>
<num>04</num>
<C>05</C>
<num>06</num>
<D>07</D>
<num>08</num>
<E>09</E>
<num>010</num>
</nums>
生成想要的正确结果:
<table border="1">
<tr>
<td>A</td>
<td>02</td>
</tr>
<tr>
<td>B</td>
<td>04</td>
</tr>
<tr>
<td>C</td>
<td>06</td>
</tr>
<tr>
<td>D</td>
<td>08</td>
</tr>
<tr>
<td>E</td>
<td>010</td>
</tr>
</table>
答案 2 :(得分:1)
好的,
我将@Dimitre Novatchev的想法与来自 [XSLT]: Rendering a node sequence as M x N table 帖子的帖子的答案和@ Tomalak's结合起来。我非常喜欢使用$perRow
变量的@ Tomalak解决方案和<xsl:template name="filler">
模板来处理空单元格。
根据@Dimitre Novatchev提出的想法回答我坚持$trStartPos
。然后,我计算$lowerBoundry
和$upperBoundry
,用于累积应出现在行中的所有元素。可能有更优雅的方式进行此计算 - 如果您想出一个,请告诉我,我真的很感激!
XSLT转型
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- Select only required elements -->
<xsl:variable name="tableData"
select="/nums/A | /nums/B | /nums/C | /nums/D | /nums/E "/>
<xsl:variable name="perRow" select="2"/>
<xsl:template match="/">
<table border="1">
<tbody>
<xsl:apply-templates
select="$tableData[position() mod $perRow = 1]" mode="tr"/>
</tbody>
</table>
</xsl:template>
<xsl:template match="nums/*" mode="tr">
<xsl:variable name="trStartPos" select="position()" />
<xsl:variable name="upperBoundry" select="$trStartPos * $perRow" />
<xsl:variable name="lowerBoundry" select="$upperBoundry - $perRow" />
<tr>
<xsl:variable name="tdsData"
select="$tableData[(position() > $lowerBoundry) and (position() <= $upperBoundry)]" />
<xsl:apply-templates select="$tdsData" mode="td"/>
<!-- fill up the last row - @Tomalak's solution -->
<xsl:if test="count($tdsData) < $perRow">
<xsl:call-template name="filler">
<xsl:with-param name="rest" select="$perRow - count($tdsData)" />
</xsl:call-template>
</xsl:if>
</tr>
</xsl:template>
<!-- Templates for specific elements could be easily added with appropriate info to
be displayed depending on the element. This one is general just to display
elements' name and value -->
<xsl:template match="nums/*" mode="td">
<td>
El. name: <xsl:value-of select="local-name()"/> -
El. value: <xsl:value-of select="."/>
</td>
</xsl:template>
<!-- @Tomalak solution (please read beginning of this answer for reference) -->
<xsl:template name="filler">
<xsl:param name="rest" select="0" />
<xsl:if test="$rest">
<td> </td>
<xsl:call-template name="filler">
<xsl:with-param name="rest" select="$rest - 1" />
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
应用于以下XML
<nums>
<A>A-01</A>
<num>02</num>
<num>03</num>
<num>04</num>
<B>B-05</B>
<num>06</num>
<num>07</num>
<C>C-08</C>
<num>09</num>
<D>D-10</D>
<num>11</num>
<num>12</num>
<num>13</num>
<E>E-14</E>
<num>15</num>
</nums>
会产生以下输出
<table border="1">
<tbody>
<tr>
<td>
El. name: A -
El. value: A-01
</td>
<td>
El. name: B -
El. value: B-05
</td>
</tr>
<tr>
<td>
El. name: C -
El. value: C-08
</td>
<td>
El. name: D -
El. value: D-10
</td>
</tr>
<tr>
<td>
El. name: E -
El. value: E-14
</td>
<td> </td>
</tr>
</tbody>
</table>