XSL生成嵌套列表-重复项

时间:2018-10-24 09:57:56

标签: xml xslt xslt-1.0

嗨,我有一个简单的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不允许我发布,因为显然需要更多详细信息。

1 个答案:

答案 0 :(得分:0)

问题出在这条线上。...

 <xsl:apply-templates select="DataRow[not(DataRow/parentid_visio)]"/>

这是说“选择没有DataRow的任何DataRow/parentid_visio作为孩子”。但是,XML中没有DataRow甚至没有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 = '']"/>

(在最后一种情况下,如果XML中不存在parentid_visio,则parentid_visio = ''返回false,因此该行将不会被选中)。