首页 > 解决方案 > 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 不允许我发布,因为显然需要更多细节。

标签: xmlxsltxslt-1.0

解决方案


问题出在这条线....

 <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_visioXML 中不存在,则parentid_visio = ''返回 false,因此不会选择该行)。


推荐阅读