【问题标题】:XSLT multi-level list depending on category nameXSLT 多级列表取决于类别名称
【发布时间】:2019-10-01 20:18:46
【问题描述】:

我想根据类别名称构建多级嵌套列表。这是我的 xml:

<UserDefinedTable xmlns="DotNetNuke/UserDefinedTable">
  <Data>
    <UserDefinedRowId>28</UserDefinedRowId>
    <Category>KatOne</Category>
    <Title>Level 1</Title>
  </Data>
  <Data>
    <UserDefinedRowId>29</UserDefinedRowId>
    <Category>KatOneSub</Category>
    <Title>Level 2</Title>
  </Data>
  <Data>
    <UserDefinedRowId>30</UserDefinedRowId>
    <Category>KatOneSub</Category>
    <Title>Level 2</Title>
  </Data>
  <Data>
    <UserDefinedRowId>31</UserDefinedRowId>
    <Category>KatTwo</Category>
    <Title>Level 1</Title>
  </Data>
  <Data>
    <UserDefinedRowId>32</UserDefinedRowId>
    <Category>KatTwoSub</Category>
    <Title>Level 2</Title>
  </Data>
  <Data>
    <UserDefinedRowId>33</UserDefinedRowId>
    <Category>KatTwoSub</Category>
    <Title>Level 2</Title>
  </Data>
</UserDefinedTable>

这是我对 XSLT 模板的尝试:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:udt="DotNetNuke/UserDefinedTable" exclude-result-prefixes="udt">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />

  <xsl:variable name="prefix_param">udt_<xsl:value-of select="//udt:Context/udt:ModuleId" />_param</xsl:variable>

  <xsl:template match="udt:Data" mode="list">

    <xsl:for-each select="udt:Data">
    <li>
        <span>KatUpper</span>

        <ul class="level-two">
            <xsl:for-each select="udt:Data">
                <li>
                    KatSub
                </li>
            </xsl:for-each>
        </ul>                   

    </li>
    </xsl:for-each>

  </xsl:template>

  <xsl:template match="/udt:UserDefinedTable">
    <xsl:variable name="currentData" select="udt:Data" />
    <xsl:if test="$currentData">
    <ul class="my-list">
      <xsl:apply-templates select="$currentData" mode="list">
      </xsl:apply-templates>
    </ul>
    </xsl:if>
  </xsl:template>

  <xsl:template name="EditLink">
    <xsl:if test="udt:EditLink">
      <a href="{udt:EditLink}">
        <img border="0" alt="edit" src="{//udt:Context/udt:ApplicationPath}/images/edit.gif" />
      </a>
    </xsl:if>
  </xsl:template>
</xsl:stylesheet>

我想创建一个 foreach 来检查类别名称是否与这个或那个相匹配,然后它会停留在上层,并且在每次迭代中我会检查类别名称是否有一个嵌套列表:

类似这样的:

<ul class="my-list">
    <li>
        <span>KatOne</span>

        <ul clasS="levelTwo">
            <li>
                KatOneSub
            </li>
            <li>
                KatOneSub
            </li>
            <li>
                KatOneSub
            </li>
        </ul>
    </li>
    <li>
        <span>KatTwo</span>

        <ul clasS="levelTwo">
            <li>
                KatTwoSub
            </li>
            <li>
                KatTwoSub
            </li>
        </ul>
    </li>
</ul>

【问题讨论】:

  • 您可以使用 XSLT 2.0 吗?将xsl:for-each-group 与“group-starting-with”一起使用会更容易解决。另外,你可以有超过 2 层的嵌套吗?谢谢!
  • 是的,我是。不,最多 2 个级别

标签: xslt


【解决方案1】:

您当前的问题是,在匹配udt:Data 的模板中,您执行&lt;xsl:for-each select="udt:Data"&gt;,但这将寻找当前Data 元素的子元素,该元素也称为Data。你真的应该在这里寻找兄弟姐妹。

在 XSLT 1.0 中,您可以使用键根据前面的第一个“级别 1”项来查找“级别 2”项

<xsl:key name="level2" 
         match="udt:Data[udt:Title='Level 2']" 
         use="preceding-sibling::udt:Data[udt:Title='Level 1'][1]/udt:UserDefinedRowId" />

然后您将首先选择“级别 1”项目

<xsl:variable name="currentData" select="udt:Data[udt:Title='Level 1']" />

<xsl:apply-templates select="$currentData" mode="list" />

然后,要获取当前“级别 1”项目的“级别 2”项目,您可以使用 key

<xsl:for-each select="key('level2', udt:UserDefinedRowId)">

试试这个 XSLT

<xsl:stylesheet version="1.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                xmlns:udt="DotNetNuke/UserDefinedTable" 
                exclude-result-prefixes="udt">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />

  <xsl:key name="level2" 
           match="udt:Data[udt:Title='Level 2']" 
           use="preceding-sibling::udt:Data[udt:Title='Level 1'][1]/udt:UserDefinedRowId" />

  <xsl:template match="udt:Data" mode="list">
    <li>
      <span>
        <xsl:value-of select="udt:Category" />
      </span>
      <xsl:if test="key('level2', udt:UserDefinedRowId)">
        <ul class="levelTwo">
          <xsl:for-each select="key('level2', udt:UserDefinedRowId)">
            <li>
              <span>
                <xsl:value-of select="udt:Category" />
              </span>
            </li>
          </xsl:for-each>
        </ul>
      </xsl:if>
    </li>      
  </xsl:template>

  <xsl:template match="/udt:UserDefinedTable">
    <xsl:variable name="currentData" select="udt:Data[udt:Title='Level 1']" />
    <xsl:if test="$currentData">
      <ul class="my-list">
        <xsl:apply-templates select="$currentData" mode="list" />
      </ul>
    </xsl:if>
  </xsl:template>
</xsl:stylesheet>

请注意,如果您有更好的方法来识别级别 1 和级别 2 元素,则应相应地更改 Title="Level 1" 等表达式。

【讨论】:

  • 我在这里看到的第一个问题是,我无法按标题选择/comapre,每次都必须使用类别,只取决于类别是 KatOne、KatTwo、KatThree 和子列表是否添加了“子”最后,标题会有所不同,这些是测试标题
  • 您确实需要一种明确的方式来识别您的“1 级”和“2 级”项目是什么,否则您将遇到问题。您对输入 XML 有任何控制权吗?向每个 Data 项目添加 Level 元素将是最简单的解决方案。
  • 我可以,我们称之为“item-level”,所以我们为 level 1 和 level 2 保留相同的类别并定义一个定义 level 的新属性?
  • 是的,可以。然后xsl:for-each-group 变为&lt;xsl:for-each-group select="Data" group-starting-with="Data[item-level='1']"&gt;,其他一切都可以保持不变。
  • 我改变了它,它对我不起作用,事实上我得到一个编译错误,for-each-group can't be nested inside xsl:if
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-30
  • 1970-01-01
  • 2019-06-22
  • 1970-01-01
  • 2020-04-01
相关资源
最近更新 更多