XML
<Action>
<Step>
<Obj>UC_A</Obj>
<Step>
<Obj>abc</Obj>
<Step>
<Obj>bcd</Obj>
</Step>
</Step>
</Step>
<Step>
<Obj>cde</Obj>
</Step>
<Step>
<Obj>UC_B</Obj>
</Step>
<Step>
<Obj>def</Obj>
<Step>
<Obj>efg</Obj>
</Step>
</Step>
<Step>
<Obj>UC_C</Obj>
<Step>
<Obj>pqr</Obj>
</Step>
<Step>
<Obj>xyz</Obj>
<Step>
<Obj>uvw</Obj>
</Step>
</Step>
</Step>
</Action>
我的XSL
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" omit-xml-declaration="yes" version="5.0" doctype-system="about:legacy-compat" encoding="utf-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="group" match="Step[not(starts-with(Obj, 'UC_'))]" use="generate-id(ancestor::Step[starts-with(Obj, 'UC_')][1])"/>
<xsl:template match="Action">
<html>
<head>
<style type="text/css">
table { table-layout:auto; border-collapse:collapse; font-family:Arial; }
td { vertical-align:top; border:1px solid Silver; padding:0pt; font-size:9pt; padding-right:3px; padding-left:3px; }
</style>
</head>
<body>
<table>
<xsl:apply-templates select="Step[starts-with(Obj, 'UC_')]"/>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="Step[starts-with(Obj, 'UC_')]">
<xsl:variable name="group" select="key('group', generate-id())"/>
<tr>
<td rowspan="{1 + count($group)}">
<xsl:number count="Step[starts-with(Obj, 'UC_')]"/>
</td>
<td>
<xsl:value-of select="Obj"/>
</td>
</tr>
<xsl:apply-templates select="$group" />
</xsl:template>
<xsl:template match="Step[not(starts-with(Obj, 'UC_'))]">
<tr>
<td>
<xsl:value-of select="Obj"/>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
问题
预期的HTML
实际HTML
我当前的XSL并未考虑与UC_ *节点处于同一级别的节点(如cde)或处于第二级的节点。我想为一组UC_节点设置一个rowspan。
我不想使用分组,因为效率不高(我的实际xml很大)
答案 0 :(得分:1)
目前您的密钥只是查看祖先节点,但Step
个节点没有&#34; UC _&#34;作为祖先的价值。在这种情况下,您需要查找前面的元素,而不是祖先。
现在,您可以将密钥写为,以查找祖先不存在的前一个元素:
<xsl:key name="group"
match="Step[not(starts-with(Obj, 'UC_'))]"
use="generate-id(ancestor::Step[starts-with(Obj, 'UC_')][1]
| self::*[not(ancestor::Step[starts-with(Obj, 'UC_')])]/preceding::Step[starts-with(Obj, 'UC_')][1])"/>
但这看起来并不特别好看。你可以通过为没有祖先
的单独键来略微简化一些事情<xsl:key name="group2"
match="Step[not(ancestor::Step[starts-with(Obj, 'UC_')])][not(starts-with(Obj, 'UC_'))]"
use="generate-id(preceding::Step[starts-with(Obj, 'UC_')][1])"/>
然后,您只需更改group
变量即可使用此密钥:
<xsl:variable name="group" select="key('group', generate-id())|key('group2', generate-id())"/>
作为最后的替代方案,您可能不需要一个密钥来键入&#34; UC _&#34;的后代节点。价值节点。相反,定义一个键以在同一级别上查找前面的兄弟姐妹....
<xsl:key name="group"
match="Step[not(starts-with(Obj, 'UC_'))]"
use="generate-id(preceding-sibling::Step[starts-with(Obj, 'UC_')][1])"/>
然后您的group
变量定义如下:
<xsl:variable name="group" select="descendant::Step|key('group', generate-id())/descendant-or-self::Step"/>
试试这个XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" omit-xml-declaration="yes" version="5.0" doctype-system="about:legacy-compat" encoding="utf-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="group"
match="Step[not(starts-with(Obj, 'UC_'))]"
use="generate-id(preceding-sibling::Step[starts-with(Obj, 'UC_')][1])"/>
<xsl:template match="Action">
<html>
<body>
<table border="1">
<xsl:apply-templates select="Step[starts-with(Obj, 'UC_')]"/>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="Step[starts-with(Obj, 'UC_')]">
<xsl:variable name="group" select="descendant::Step|key('group', generate-id())/descendant-or-self::Step"/>
<tr>
<td rowspan="{1 + count($group)}">
<xsl:number count="Step[starts-with(Obj, 'UC_')]"/>
</td>
<td>
<xsl:value-of select="Obj"/>
</td>
</tr>
<xsl:apply-templates select="$group" />
</xsl:template>
<xsl:template match="Step[not(starts-with(Obj, 'UC_'))]">
<tr>
<td>
<xsl:value-of select="Obj"/>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>