给定一个具有以下结构的输入xml文件:
<root>
<record row="1" col="1" val="1" />
<record row="1" col="2" val="2" />
<record row="1" col="3" val="3" />
<record row="1" col="n" val="4" />
<record row="2" col="1" val="5" />
<record row="2" col="3" val="6" />
<record row="2" col="n" val="7" />
<record row="n" col="2" val="8" />
<record row="n" col="3" val="9" />
<record row="n" col="n" val="10" />
</root>
如何使用XSLT输出以下结构?
<root>
<row id="1">
<col id="1">1</col>
<col id="2">2</col>
<col id="3">3</col>
<col id="n">4</col>
</row>
<row id="2">
<col id="1">5</col>
<col id="2"></col>
<col id="3">6</col>
<col id="n">7</col>
</row>
<row id="n">
<col id="1"></col>
<col id="2">8</col>
<col id="3">9</col>
<col id="n">10</col>
</row>
</root>
[注意即使输入中没有相关元素,如何输出所有列
编辑:在我的例子中,我可能通过使用数字和字母引起了混淆。我正在寻找的解决方案需要处理非数字的行和列属性。答案 0 :(得分:3)
这个问题的答案显示了解决问题的可能方法:
xslt: How could I use xslt to create a table with multiple columns and rows?
编辑:包含链接问题中所见技术的解决方案如下。
我假设:
@row
和@col
属性是递增数字,用于定义表中记录的位置,并且它们实际上不能包含字符串"n"
。因此,它们在整个文档中并不是唯一的,这使得它们不适合作为HTML @id
属性。我在输出中用@title
属性替换它们。@row
连续性中的空隙不会产生空行),只有隐式空单元格。 @row
和@col
组合都是唯一的。此XSLT 1.0转换:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<!-- prepare some keys for later use -->
<xsl:key name="kRecordsByRow" match="record" use="@row" />
<xsl:key name="kRecordsByPos" match="record" use="concat(@row, ',', @col)" />
<!-- find out the highest @col number -->
<xsl:variable name="vMaxCol">
<xsl:for-each select="/root/record">
<xsl:sort select="@col" data-type="number" order="descending" />
<xsl:if test="position() = 1">
<xsl:value-of select="@col" />
</xsl:if>
</xsl:for-each>
</xsl:variable>
<!-- select the <record>s that are the first in their rows -->
<xsl:variable name="vRows" select="
/root/record[
generate-id()
=
generate-id(key('kRecordsByRow', @row)[1])
]
" />
<!-- output basic table structure -->
<xsl:template match="/root">
<table>
<xsl:for-each select="$vRows">
<xsl:sort select="@row" data-type="number" />
<tr title="{@row}">
<xsl:call-template name="td" />
</tr>
</xsl:for-each>
</table>
</xsl:template>
<!-- output the right number of <td>s in each row, empty or not -->
<xsl:template name="td">
<xsl:param name="col" select="1" />
<td title="{$col}">
<xsl:value-of select="key('kRecordsByPos', concat(@row, ',', $col))/@val" />
</td>
<xsl:if test="$col < $vMaxCol">
<xsl:call-template name="td">
<xsl:with-param name="col" select="$col + 1" />
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
...当应用于此(稍加修改)输入时:
<root>
<record row="1" col="1" val="1" />
<record row="1" col="2" val="2" />
<record row="1" col="3" val="3" />
<record row="1" col="4" val="4" />
<record row="2" col="1" val="5" />
<record row="2" col="3" val="6" />
<record row="2" col="4" val="7" />
<record row="3" col="2" val="8" />
<record row="3" col="3" val="9" />
<record row="3" col="4" val="10" />
</root>
...生产:
<table>
<tr title="1">
<td title="1">1</td>
<td title="2">2</td>
<td title="3">3</td>
<td title="4">4</td>
</tr>
<tr title="2">
<td title="1">5</td>
<td title="2"></td>
<td title="3">6</td>
<td title="4">7</td>
</tr>
<tr title="3">
<td title="1"></td>
<td title="2">8</td>
<td title="3">9</td>
<td title="4">10</td>
</tr>
</table>
<record>
组的第一个@row
<xsl:key>
用于根据位置确定记录<td>
s,与命名位置<record>
的实际存在无关答案 1 :(得分:2)
XSLT 2.0解决方案
此转化:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
>
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="vDoc" as="document-node()"
select="/"/>
<xsl:key name="kColsByRow" match="@col"
use="../@row"/>
<xsl:key name="kRecByRowCol" match="record"
use="concat(@row,'+',@col)"/>
<xsl:template match="/*">
<root>
<xsl:for-each-group select="*/@row"
group-by=".">
<xsl:sort select="current-grouping-key()"
data-type="number"/>
<xsl:variable name="vRow"
select="current-grouping-key()"/>
<row idd="{$vRow}">
<xsl:for-each select=
"1 to max(key('kColsByRow',$vRow)/xs:integer(.))">
<col idd="{.}">
<xsl:value-of select=
"key('kRecByRowCol',
concat($vRow,'+',.),
$vDoc
)
/
@col
"
/>
</col>
</xsl:for-each>
</row>
</xsl:for-each-group>
</root>
</xsl:template>
</xsl:stylesheet>
应用于此XML文档时:
<root>
<record row="1" col="1" val="1" />
<record row="1" col="2" val="2" />
<record row="1" col="3" val="3" />
<record row="1" col="10" val="4" />
<record row="2" col="1" val="5" />
<record row="2" col="3" val="6" />
<record row="2" col="10" val="7" />
<record row="10" col="2" val="8" />
<record row="10" col="3" val="9" />
<record row="10" col="10" val="10" />
</root>
产生想要的结果:
<root>
<row idd="1">
<col idd="1">1</col>
<col idd="2">2</col>
<col idd="3">3</col>
<col idd="4"/>
<col idd="5"/>
<col idd="6"/>
<col idd="7"/>
<col idd="8"/>
<col idd="9"/>
<col idd="10">10</col>
</row>
<row idd="2">
<col idd="1">1</col>
<col idd="2"/>
<col idd="3">3</col>
<col idd="4"/>
<col idd="5"/>
<col idd="6"/>
<col idd="7"/>
<col idd="8"/>
<col idd="9"/>
<col idd="10">10</col>
</row>
<row idd="10">
<col idd="1"/>
<col idd="2">2</col>
<col idd="3">3</col>
<col idd="4"/>
<col idd="5"/>
<col idd="6"/>
<col idd="7"/>
<col idd="8"/>
<col idd="9"/>
<col idd="10">10</col>
</row>
</root>