如何使用XSLT从XML数据创建TreeView

时间:2012-01-06 13:40:37

标签: html xml xslt treeview grouping

我有以下形式的XML数据:

<table>
 <col>
  <name>Addresses</name>
 </col>
 <col>
  <name>Addresses/Address1</name>
 </col>
 <col>
  <name>Addresses/Address2</name>
 </col>
 <col>
  <name>Addresses/Address1/Flat Number</name>
 </col>
 <col>
  <name>Employee Name</name>
 </col>
 <col>
  <name>Phone Number</name>
 </col>
 <col>
  <name>Profession</name>
 </col>
 <col>
  <name>Employee Name/First Name</name>
 </col>
 <col>
  <name>Employee Name/Last Name</name>
 </col>
 <col>
  <name>Employee Name/First_Name</name>
 </col>
 <col>
  <name>Accounts/Account Name/First/Saving</name>
 </col>
 <col>
  <name>Accounts/Account_Name/Second</name>
 </col>
</table> 

现在我想在这个XML上使用XSLT在HTML中创建一个类似树视图的结构。 Treeview的结构类似于以下结构:

  • 地址
    • 地址1
    • 地址2
  • 员工姓名
    • 名字
    • 姓氏
  • 帐户
    • 帐户名称

请注意,第一次出现“/”之前的子字符串是树视图的第一级节点,第一次出现“/”后的子字符串是匹配的第一级节点的第二级节点,这只是一个2级别树视图。

此外,显示的值是唯一的。即使值在XML中重复,我们也只需要选择唯一的值。还需要考虑的另一个条件是,“”的值与没有“”的情况相同,如示例中所示:“First Name”和“First_Name”,因此我们需要在替换后显示值“ - “with”“。

<xsl:variable name="currentNode" select="//table/col" />
<xsl:key name="uniqueCategoryKey" match="record" use="name"/>
<xsl:key name="uniqueSubCategoryKey" match="record" use="substring-before(substring-after(concat(name,'/'),'/'),'/')"/>
<xsl:template match="/">
<xsl:call-template name="treeTemplate" />
</xsl:template>

<xsl:template name="treeTemplate">


  <div id ="newtreeview">
    <ul>
      <xsl:for-each select="$currentNode[generate-id() = generate-id(key('uniqueCategoryKey', name))]">

        <xsl:variable name="category" select="name"/>

        <xsl:if test="string-length($category) > 0 and not(contains($category,'/'))">
          <li>
            <a href="#">
              <xsl:value-of select="$category"/>
            </a>
            <xsl:if test="//record[contains(name, concat($category,'/'))]">
              <ul>

                <xsl:for-each select="$currentNode[generate-id() = generate-id(key('uniqueSubCategoryKey', substring-before(substring-after(concat(name,'/'),'/'),'/')))]">

                  <li>
                    <a href="#">
                      <xsl:variable name="subcat">
                        <xsl:call-template name="string-replace-all">
                          <xsl:with-param name="text" select="string(substring-before(substring-after(concat(name,'/'),'/'),'/'))" />
                          <xsl:with-param name="replace" select="'_'" />
                          <xsl:with-param name="by" select="' '" />
                        </xsl:call-template>
                      </xsl:variable>
                      <xsl:value-of select="$subcat"/>


                    </a>
                  </li>
                </xsl:for-each>
              </ul>
            </xsl:if>
          </li>
        </xsl:if>
       </xsl:for-each>
    </ul>
  </div>

</xsl:template>
<xsl:template name="string-replace-all">
<xsl:param name="text" />
<xsl:param name="replace" />
<xsl:param name="by" />
<xsl:choose>
  <xsl:when test="contains($text, $replace)">
    <xsl:value-of select="substring-before($text,$replace)" />
    <xsl:value-of select="$by" />
    <xsl:call-template name="string-replace-all">
      <xsl:with-param name="text"
      select="substring-after($text,$replace)" />
      <xsl:with-param name="replace" select="$replace" />
      <xsl:with-param name="by" select="$by" />
    </xsl:call-template>
  </xsl:when>
  <xsl:otherwise>
    <xsl:value-of select="$text" />
  </xsl:otherwise>
</xsl:choose>
</xsl:template>

问题是,这段代码给了我一个像

这样的输出
  • 地址
      • -
    • 地址1
    • 地址2
  • 员工姓名
      • -
    • 名字
    • 名字
    • 姓氏
  • 帐户
    • 帐户名称
    • 帐户名称

请帮我解决这个问题。

先谢谢。

1 个答案:

答案 0 :(得分:2)

此XSLT 1.0转换

<xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
     <xsl:strip-space elements="*"/>

     <xsl:key name="kCatFromName" match="name"
      use="substring-before(concat(.,'/'), '/')"/>

     <xsl:key name="kValFromName" match="name[contains(., '/')]"
      use="concat(substring-before(.,'/'),
           '+',
           translate(
               substring-before
                 (concat(substring-after(.,'/'), '/'),
                  '/'
                 ),
               '_',
               ' '
                       )
                )
          "/>

     <xsl:template match="/*">
      <ul>
         <xsl:apply-templates mode="cat" select=
          "*/name
             [generate-id()
             =
              generate-id(key('kCatFromName',
                               substring-before(concat(.,'/'), '/')
                               )[1]
                        )
             ]
          "/>
        </ul>
     </xsl:template>

     <xsl:template match="name" mode="cat">
      <xsl:variable name="vCat" select=
      "substring-before(concat(.,'/'), '/')"/>
      <li><xsl:value-of select="$vCat"/></li>

       <xsl:variable name="vInThisCat" select=
       "key('kCatFromName', $vCat)
         [generate-id()
         =
          generate-id(key('kValFromName',
                          concat(substring-before(.,'/'),
                                 '+',
                                 translate(
                                           substring-before
                                            (concat(substring-after(.,'/'), '/'),
                                             '/'
                                            ),
                                            '_',
                                            ' '
                                            )
                                )
                          )[1]
                      )
         ]"/>

         <xsl:if test="$vInThisCat">
        <ul>
          <xsl:apply-templates mode="val" select="$vInThisCat"/>
         </ul>
       </xsl:if>
     </xsl:template>

      <xsl:template match="name" mode="val">
        <li>
          <xsl:value-of select=
          "translate(substring-before
                (concat(substring-after(.,'/'), '/'),
                 '/'
                ),
               '_',
               ' '
               )
          "/>
        </li>
      </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档

<table>
    <col>
        <name>Addresses</name>
    </col>
    <col>
        <name>Addresses/Address1</name>
    </col>
    <col>
        <name>Addresses/Address2</name>
    </col>
    <col>
        <name>Addresses/Address1/Flat Number</name>
    </col>
    <col>
        <name>Employee Name</name>
    </col>
    <col>
        <name>Phone Number</name>
    </col>
    <col>
        <name>Profession</name>
    </col>
    <col>
        <name>Employee Name/First Name</name>
    </col>
    <col>
        <name>Employee Name/Last Name</name>
    </col>
    <col>
        <name>Employee Name/First_Name</name>
    </col>
    <col>
        <name>Accounts/Account Name/First/Saving</name>
    </col>
    <col>
        <name>Accounts/Account_Name/Second</name>
    </col>
</table>

生成想要的正确结果

<ul>
   <li>Addresses</li>
   <ul>
      <li>Address1</li>
      <li>Address2</li>
   </ul>
   <li>Employee Name</li>
   <ul>
      <li>First Name</li>
      <li>Last Name</li>
   </ul>
   <li>Phone Number</li>
   <li>Profession</li>
   <li>Accounts</li>
   <ul>
      <li>Account Name</li>
   </ul>
</ul>

,浏览器将其显示为

       
  • 地址
  •    
            
    • 地址1
    •       
    • 地址2
    •    
       
  • 员工姓名
  •    
            
    • 名字
    •       
    • 姓氏
    •    
       
  • 电话号码
  •    
  • 行业
  •    
  • 帐户
  •    
            
    • 帐户名称
    •