如何使用此xml并为每个“section”元素创建一个包含列的表,然后使用xslt显示该列中的所有“document”元素?
<Documents>
<Section>
<SectionName>Green</SectionName>
<Document>
<FileName>Tier 1 Schedules</FileName>
</Document>
<Document>
<FileName>Tier 3 Schedules</FileName>
</Document>
<Document>
<FileName>Setback Schedule</FileName>
</Document>
<Document>
<FileName>Tier 2 Governance</FileName>
</Document>
</Section>
<Section>
<SectionName>MRO/Refurb</SectionName>
<Document>
<FileName>Tier 2 Governance</FileName>
</Document>
</Section>
谢谢, 人
答案 0 :(得分:3)
此解决方案不使用递归,并使用一些有用的XSLT技术,例如Muenchian分组,键,查找最大值和迭代而不递归。
此转化:
<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:key name="kSectsByValue" match="SectionName"
use="."/>
<xsl:key name="kDocBySect" match="Document"
use="../SectionName"/>
<xsl:variable name="vCols" select=
"/*/*/SectionName
[generate-id()
=
generate-id(key('kSectsByValue',.)[1])
]"/>
<xsl:variable name="vMaxRows">
<xsl:for-each select="$vCols">
<xsl:sort data-type="number" order="descending"
select="count(key('kDocBySect', .))" />
<xsl:if test="position() = 1">
<xsl:value-of select="count(key('kDocBySect', .))"/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:template match="/">
<table>
<tr>
<xsl:apply-templates select="$vCols"/>
</tr>
<xsl:for-each select=
"(/*/*/Document)[not(position() > $vMaxRows)]">
<tr>
<xsl:variable name="vPos" select="position()"/>
<xsl:for-each select="$vCols">
<td>
<xsl:value-of select=
"../Document[$vPos]/FileName"/>
</td>
</xsl:for-each>
</tr>
</xsl:for-each>
</table>
</xsl:template>
<xsl:template match="SectionName">
<td>
<xsl:value-of select="." />
</td>
</xsl:template>
</xsl:stylesheet>
应用于原始XML文档(更正为格式良好):
<Documents>
<Section>
<SectionName>Green</SectionName>
<Document>
<FileName>Tier 1 Schedules</FileName>
</Document>
<Document>
<FileName>Tier 3 Schedules</FileName>
</Document>
<Document>
<FileName>Setback Schedule</FileName>
</Document>
<Document>
<FileName>Tier 2 Governance</FileName>
</Document>
</Section>
<Section>
<SectionName>MRO/Refurb</SectionName>
<Document>
<FileName>Tier 2 Governance</FileName>
</Document>
</Section>
</Documents>
产生所需的结果:
<table>
<tr>
<td>Green</td>
<td>MRO/Refurb</td>
</tr>
<tr>
<td>Tier 1 Schedules</td>
<td>Tier 2 Governance</td>
</tr>
<tr>
<td>Tier 3 Schedules</td>
<td/>
</tr>
<tr>
<td>Setback Schedule</td>
<td/>
</tr>
<tr>
<td>Tier 2 Governance</td>
<td/>
</tr>
</table>
请注意:
我们使用Muenchian method for grouping 来查找所有不同的列名,而不是依赖于XML文档中的唯一列名称。
Keys 用于Muenchian分组和查找属于某列的所有项目。
找到最大行数并保存在变量$vMaxRows
我们迭代N次以生成表格的N行 - 不使用递归!
通过将模板应用于列中位置为N
的所有列项来输出N
行。
答案 1 :(得分:1)
这是一种可能的解决方案:
<xsl:variable name="vCountRows">
<xsl:apply-templates select="Documents/Section[1]" mode="findmax" />
</xsl:variable>
<xsl:variable name="vCountCols" select="count(Documents/Section)" />
<xsl:template match="/Documents">
<table r="{$vCountRows}" s="{$vCountCols}">
<thead>
<xsl:call-template name="create-thead" />
</thead>
<tbody>
<xsl:call-template name="create-tr" />
</tbody>
</table>
</xsl:template>
<xsl:template name="create-thead">
<tr>
<xsl:apply-templates select="Section" />
</tr>
</xsl:template>
<xsl:template match="Section">
<th><xsl:value-of select="SectionName" /></th>
</xsl:template>
<xsl:template name="create-tr">
<xsl:param name="row" select="1" />
<tr>
<xsl:call-template name="create-td">
<xsl:with-param name="row" select="$row" />
</xsl:call-template>
</tr>
<xsl:if test="$row < $vCountRows">
<xsl:call-template name="create-tr">
<xsl:with-param name="row" select="$row + 1" />
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="create-td">
<xsl:param name="col" select="1" />
<xsl:param name="row" select="1" />
<td>
<xsl:value-of select="Section[$col]/Document[$row]/FileName" />
</td>
<xsl:if test="$col < $vCountCols">
<xsl:call-template name="create-td">
<xsl:with-param name="col" select="$col + 1" />
<xsl:with-param name="row" select="$row" />
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template match="Section" mode="findmax">
<xsl:variable name="c" select="count(Document)" />
<xsl:variable name="next" select="following-sibling::Section[count(Document) > $c][1]" />
<xsl:choose>
<xsl:when test="$next">
<xsl:apply-templates select="$next" mode="findmax" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$c" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
根据您的输入,它会产生:
<table>
<thead>
<tr>
<td>Green</td>
<td>MRO/Refurb</td>
</tr>
</thead>
<tbody>
<tr>
<td>Tier 1 Schedules</td>
<td>Tier 2 Governance</td>
</tr>
<tr>
<td>Tier 3 Schedules</td>
<td></td>
</tr>
<tr>
<td>Setback Schedule</td>
<td></td>
</tr>
<tr>
<td>Tier 2 Governance</td>
<td></td>
</tr>
</tbody>
</table>
一般的apporach是这样的:
<xsl:template match="Section" mode="findmax">
中,它以递归方式查找具有最大<Document>
个节点数的节<Section>
s的数量)<tr>
的模板,并一直调用自己,直到创建了所有必要的行<td>
s。它一直调用自己直到达到最大列数(从步骤2开始)算法:
存在一个更高效的版本(可能使用<xsl:key>
),我将更多地考虑优化我的版本。