xml - XSL 生成嵌套列表 - 项目重复
问题描述
您好我有一个简单的 XSL 样式表,它从一个平面 XML 文件构建一个嵌套列表(文件必须是平面的 - 这是软件输出它的方式)。
然而,在列表的末尾,它重复了所有项目,我不明白为什么。我仅限于使用 XSL V1.0。
XML:
<QueryResults ReportName="Document Hierarchy Visio" ReportID="216">
<Data RecordCount="186">
<DataRow index="1">
<parentid_visio></parentid_visio>
<childid_visio>111</childid_visio>
<parent_id>1</parent_id>
<child_id>1</child_id>
<formname>Patient</formname>
<lvl>1</lvl>
<patrank>1</patrank>
</DataRow>
<DataRow index="2">
<parentid_visio>111</parentid_visio>
<childid_visio>213</childid_visio>
<parent_id>1</parent_id>
<child_id>3</child_id>
<formname>Alias</formname>
<lvl>2</lvl>
<patrank>1</patrank>
</DataRow>
<DataRow index="3">
<parentid_visio>111</parentid_visio>
<childid_visio>214</childid_visio>
<parent_id>1</parent_id>
<child_id>4</child_id>
<formname>Address</formname>
<lvl>2</lvl>
<patrank>1</patrank>
</DataRow>
</Data>
</QueryResults>
XSL:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="child" match="DataRow" use="parentid_visio" />
<xsl:template match="Data">
<div class="tree">
<ul>
<xsl:apply-templates select="DataRow[not(DataRow/parentid_visio)]"/>
</ul>
</div>
</xsl:template>
<xsl:template match="DataRow">
<li>
<a href="#"><xsl:value-of select="formname"/></a>
<xsl:if test="key('child', childid_visio)">
<ul>
<xsl:apply-templates select="key('child', childid_visio)[not(DataRow/parentid_visio)]"/>
</ul>
</xsl:if>
</li>
</xsl:template>
</xsl:stylesheet>
它应该给出一个输出
<div class="tree">
<ul>
<li><a href="#">Patient</a>
<ul>
<li><a href="#">Alias</a></li>
<li><a href="#">Address</a></li>
<li><a href="#">Alert</a></li>
<li><a href="#">Contact</a></li>
<li><a href="#">GP Detail</a></li>
<li><a href="#">School Detail</a></li>
<li><a href="#">Other Agency</a></li>
</ul>
</li>
</ul>
</div>
而是返回:
<div class="tree">
<ul>
<li><a href="#">Patient</a><ul>
<li><a href="#">Alias</a></li>
<li><a href="#">Address</a></li>
<li><a href="#">Alert</a></li>
<li><a href="#">Contact</a></li>
<li><a href="#">GP Detail</a></li>
<li><a href="#">School Detail</a></li>
<li><a href="#">Other Agency</a></li>
</ul>
</li>
<li><a href="#">Alias</a></li>
<li><a href="#">Address</a></li>
<li><a href="#">Alert</a></li>
<li><a href="#">Contact</a></li>
<li><a href="#">GP Detail</a></li>
<li><a href="#">School Detail</a></li>
<li><a href="#">Other Agency</a></li>
</ul>
</div>
我哪里错了?我不确定为什么最后会重复这个过程。这是一些额外的文本,因为 stackoverflow 不允许我发布,因为显然需要更多细节。
解决方案
问题出在这条线....
<xsl:apply-templates select="DataRow[not(DataRow/parentid_visio)]"/>
这就是说“选择任何DataRow
没有DataRow/parentid_visio
作为孩子的人”。但是DataRow
在你的 XML 中甚至没有一个DataRow
作为孩子,所以它选择所有行。
所以,你可以把它改成这个,所以它只是检查parentid_visio
作为孩子:
<xsl:apply-templates select="DataRow[not(parentid_visio)]"/>
但这不起作用,因为这会检查节点是否存在,无论该节点是否包含文本,因此它<parentid_visio></parentid_visio>
返回 true,并且没有选择任何行。
您需要这样做以检查空parentid_visio
节点以及不存在的节点
<xsl:apply-templates select="DataRow[not(parentid_visio) or parentid_visio = '']"/>
或者这会做同样的事情
<xsl:apply-templates select="DataRow[not(parentid_visio != '')]"/>
或者,如果你知道parentid_visio
将永远存在......
<xsl:apply-templates select="DataRow[parentid_visio = '']"/>
(在最后一种情况下,如果parentid_visio
XML 中不存在,则parentid_visio = ''
返回 false,因此不会选择该行)。