Как создать TreeView из данных XML с использованием XSLT - PullRequest
1 голос
/ 06 января 2012

У меня есть данные 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> 

Теперь я хочу создать древовидную структуру в HTML, используя XSLT для этого XML.Структура Treeview будет похожа на следующую структуру:

  • Адреса
    • Адрес1
    • Адрес2
  • Имя сотрудника
    • Имя
    • Фамилия
  • Счета
    • Имя учетной записи

Обратите внимание, что подстрока перед первым появлением "/" является узлом первого уровня древовидной структуры, а подстрока после первого появления "/" является узлом второго уровня соответствующего узла первого уровня, и это только 2 уровняtreeview.

Кроме того, отображаемые значения являются уникальными.Даже если значения повторяются в XML, нам нужно выбрать только одно уникальное значение.Еще одно условие, которое следует учитывать, это то, что значения с «» считаются такими же, как и без «», как указано в примере: «Имя» и «Имя_Имя», поэтому нам необходимо отобразить значение после замены «-»с "".

<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 Ответ

2 голосов
/ 06 января 2012

Это преобразование 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
Имя сотрудника
  • Имя
  • Фамилия
Номер телефона Профессия Счета
  • Имя учетной записи
...