您似乎想要为每个 ANG 一个新行,因此您必须更改此设置:
<xsl:for-each select="devices/peripheral/analog">
<tr>
<td><xsl:value-of select="ANG/@point"></td>
<td><xsl:value-of select="ANG/@something"></td>
<td><xsl:value-of select="ANG/@anything"></td>
</tr>
</xsl:for-each>
到这里:
<xsl:for-each select="devices/peripheral/analog/ANG">
<tr>
<td><xsl:value-of select="@point"></td>
<td><xsl:value-of select="@something"></td>
<td><xsl:value-of select="@anything"></td>
</tr>
</xsl:for-each>
这是假设您知道所有属性。
如果所有属性都已知,这就是我将如何做一个完整的例子......
XSLT 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="upper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
<xsl:variable name="lower" select="'abcdefghijklmnopqrstuvwxyz'"/>
<xsl:template match="/*">
<html>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="peripheral|internal|external">
<div>
<h1><xsl:value-of select="translate(local-name(),$lower,$upper)"/></h1>
<xsl:apply-templates select="unit/*"/>
</div>
</xsl:template>
<xsl:template match="unit/*">
<table>
<thead>
<tr>
<th colspan="3">
<xsl:value-of select="
concat(
translate(substring(local-name(),1,1),$lower,$upper),
substring(local-name(),2),
' Board ')"/>
<xsl:number from="peripheral|internal|external" level="any"/>
</th>
</tr>
<tr>
<th>point</th>
<th>something</th>
<th>anything</th>
</tr>
</thead>
<tbody>
<xsl:for-each select="ANG">
<tr>
<td><xsl:value-of select="@point"/></td>
<td><xsl:value-of select="@something"/></td>
<td><xsl:value-of select="@anything"/></td>
</tr>
</xsl:for-each>
</tbody>
</table>
</xsl:template>
</xsl:stylesheet>
如果属性未知,我将使用Muenchian Grouping/xsl:key 为每个analog|digital 的ANG 子级创建一个唯一的属性名称列表。
我将使用该列表来确定列数(对于 colspan),填充标题列,并为每一行填充列(每个 ANG 一个新行)。
XSLT 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kAttrs" match="ANG/@*"
use="concat(generate-id(ancestor::digital|ancestor::analog),'|',local-name())"/>
<xsl:variable name="upper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
<xsl:variable name="lower" select="'abcdefghijklmnopqrstuvwxyz'"/>
<xsl:template match="/*">
<html>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="peripheral|internal|external">
<div>
<h1><xsl:value-of select="translate(local-name(),$lower,$upper)"/></h1>
<xsl:apply-templates select="unit/*"/>
</div>
</xsl:template>
<xsl:template match="unit/*">
<xsl:variable name="id" select="generate-id()"/>
<!--
String containing a unique list of attributes from ANG children
(separated by |).
Used to guarantee that each row has the right value in each column.
Example value: point|something|anything|
-->
<xsl:variable name="attrs">
<xsl:for-each select="ANG/@*[count(.|
key('kAttrs',concat($id,'|',local-name()))[1]
)=1]">
<xsl:value-of select="concat(local-name(),'|')"/>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="colspan"
select="string-length($attrs) - string-length(translate($attrs,'|',''))"/>
<xsl:message><xsl:value-of select="local-name()"/> $attrs: <xsl:value-of select="$attrs"/></xsl:message>
<table>
<thead>
<tr>
<th colspan="{$colspan}">
<xsl:value-of select="
concat(
translate(substring(local-name(),1,1),$lower,$upper),
substring(local-name(),2),
' Board ')"/>
<xsl:number from="peripheral|internal|external" level="any"/>
</th>
</tr>
<tr>
<!--Recursive template call to get the attribute names.-->
<xsl:call-template name="getVal">
<xsl:with-param name="attrs" select="$attrs"/>
<xsl:with-param name="type" select="'head'"/>
</xsl:call-template>
</tr>
</thead>
<tbody>
<!--Each ANG is a new row.-->
<xsl:for-each select="ANG">
<tr>
<!--Recursive template call to get the attribute values.-->
<xsl:call-template name="getVal">
<xsl:with-param name="attrs" select="$attrs"/>
<xsl:with-param name="type" select="'body'"/>
</xsl:call-template>
</tr>
</xsl:for-each>
</tbody>
</table>
</xsl:template>
<xsl:template name="getVal">
<xsl:param name="attrs"/>
<xsl:param name="type"/>
<xsl:variable name="currentAttr" select="substring-before($attrs,'|')"/>
<xsl:variable name="remainingAttrs" select="substring-after($attrs,'|')"/>
<xsl:choose>
<xsl:when test="$type = 'head'">
<th><xsl:value-of select="$currentAttr"/></th>
</xsl:when>
<xsl:when test="$type = 'body'">
<td><xsl:value-of select="@*[local-name()=$currentAttr]"/></td>
</xsl:when>
</xsl:choose>
<!--This is what makes the template recursive.-->
<xsl:if test="$remainingAttrs">
<xsl:call-template name="getVal">
<xsl:with-param name="attrs" select="$remainingAttrs"/>
<xsl:with-param name="type" select="$type"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
如果可以使用 XSLT 2.0,那就简单多了……
XSLT 2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<html>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="peripheral|internal|external">
<div>
<h1><xsl:value-of select="upper-case(local-name())"/></h1>
<xsl:apply-templates select="unit/*"/>
</div>
</xsl:template>
<xsl:template match="unit/*">
<!--Sequence containing a unique list of attributes from ANG children.
Used to guarantee that each row has the right value in each column.-->
<xsl:variable name="attrs" select="distinct-values(ANG/@*/local-name())"/>
<table>
<thead>
<tr>
<th colspan="{count($attrs)}">
<xsl:value-of select="
concat(
upper-case(substring(local-name(),1,1)),
substring(local-name(),2),
' Board ')"/>
<xsl:number from="peripheral|internal|external" level="any"/>
</th>
</tr>
<tr>
<xsl:for-each select="$attrs">
<th>
<xsl:value-of select="."/>
</th>
</xsl:for-each>
</tr>
</thead>
<tbody>
<xsl:for-each select="ANG">
<xsl:variable name="current" select="current()"/>
<tr>
<xsl:for-each select="$attrs">
<td>
<xsl:value-of select="$current/@*[local-name()=current()]"/>
</td>
</xsl:for-each>
</tr>
</xsl:for-each>
</tbody>
</table>
</xsl:template>
</xsl:stylesheet>
上述所有三个样式表,使用这个输入:
<devices>
<peripheral>
<unit type="1" name="foo" version="1" index="01A" address="02B" parentType="1" parentIndex="9">
<analog>
<ANG point="1" something="foo" anything="bar" />
<ANG point="2" something="oof" anything="rab" />
</analog>
<digital>
<ANG point="1" something="foo" anything="bar" />
<ANG point="2" something="oof" anything="rab" />
</digital>
</unit>
</peripheral>
<internal>
<unit type="2" name="foobar" version="2" index="90Z" address="50X" parentType="7" parentIndex="5">
<analog>
<ANG point="1" something="foo" anything="bar" />
<ANG point="2" something="oof" anything="rab" />
</analog>
<digital>
<ANG point="1" something="foo" anything="bar" />
<ANG point="2" something="oof" anything="rab" />
</digital>
</unit>
</internal>
</devices>
将产生以下输出...
<html>
<body>
<div>
<h1>PERIPHERAL</h1>
<table>
<thead>
<tr>
<th colspan="3">Analog Board 1</th>
</tr>
<tr>
<th>point</th>
<th>something</th>
<th>anything</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>foo</td>
<td>bar</td>
</tr>
<tr>
<td>2</td>
<td>oof</td>
<td>rab</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th colspan="3">Digital Board 1</th>
</tr>
<tr>
<th>point</th>
<th>something</th>
<th>anything</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>foo</td>
<td>bar</td>
</tr>
<tr>
<td>2</td>
<td>oof</td>
<td>rab</td>
</tr>
</tbody>
</table>
</div>
<div>
<h1>INTERNAL</h1>
<table>
<thead>
<tr>
<th colspan="3">Analog Board 1</th>
</tr>
<tr>
<th>point</th>
<th>something</th>
<th>anything</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>foo</td>
<td>bar</td>
</tr>
<tr>
<td>2</td>
<td>oof</td>
<td>rab</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th colspan="3">Digital Board 1</th>
</tr>
<tr>
<th>point</th>
<th>something</th>
<th>anything</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>foo</td>
<td>bar</td>
</tr>
<tr>
<td>2</td>
<td>oof</td>
<td>rab</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
要查看后两个样式表如何处理不同的输入,请开始向 ANG 元素添加新属性。