使用XSLT将XML平面化为树。仅显示一个分支

时间:2012-08-28 17:06:16

标签: xslt

我有扁平的xml结构,我需要转换为层次结构。在stackoverflow的帮助下,我能够做到这一点。 问题:是否可以仅使用相同的扁平结构显示一个分支?

这是我的xml和xsl文件:

XML

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="Stack.xsl"?>
<Items>
    <Item>
        <Id>1</Id>
        <ParentId>0</ParentId>
        <Name>1</Name>
        <SortOrder>0</SortOrder>
    </Item>
    <Item>
        <Id>2</Id>
        <ParentId>1</ParentId>
        <Name>1.1</Name>
        <SortOrder>0</SortOrder>
    </Item>
    <Item>
        <Id>3</Id>
        <ParentId>1</ParentId>
        <Name>1.2</Name>
        <SortOrder>0</SortOrder>
    </Item>
    <Item>
        <Id>4</Id>
        <ParentId>1</ParentId>
        <Name>1.3</Name>
        <SortOrder>0</SortOrder>
    </Item>
    <Item>
        <Id>5</Id>
        <ParentId>1</ParentId>
        <Name>1.4</Name>
        <SortOrder>0</SortOrder>
    </Item>
    <Item>
        <Id>6</Id>
        <ParentId>0</ParentId>
        <Name>2</Name>
        <SortOrder>0</SortOrder>
    </Item>
    <Item>
        <Id>7</Id>
        <ParentId>6</ParentId>
        <Name>2.1</Name>
        <SortOrder>0</SortOrder>
    </Item>
    <Item>
        <Id>8</Id>
        <ParentId>6</ParentId>
        <Name>2.2</Name>
        <SortOrder>0</SortOrder>
    </Item>
    <Item>
        <Id>9</Id>
        <ParentId>0</ParentId>
        <Name>3</Name>
        <SortOrder>0</SortOrder>
    </Item>
    <Item>
        <Id>10</Id>
        <ParentId>3</ParentId>
        <Name>1.2.1</Name>
        <SortOrder>0</SortOrder>
    </Item>
    <Item>
        <Id>11</Id>
        <ParentId>8</ParentId>
        <Name>2.2.1</Name>
        <SortOrder>0</SortOrder>
    </Item>
    <Item>
        <Id>11</Id>
        <ParentId>5</ParentId>
        <Name>1.4.1</Name>
        <SortOrder>0</SortOrder>
    </Item>
</Items>

XSL

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns="http://www.w3.org/1999/xhtml">

    <xsl:param name="SelectedId" select="'10'"/>
    <xsl:key name="ChildNodes" match="/Items/Item" use="ParentId"/>

    <xsl:template match="Items">
        <ul>
          <xsl:apply-templates select="Item[ParentId = 0]" />
        </ul>
    </xsl:template>

    <xsl:template match="Item">
        <li>
            <xsl:choose>
                <xsl:when test="Id = $SelectedId">
                    <b><xsl:value-of select="Name" /></b>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="Name" />
                </xsl:otherwise>
            </xsl:choose>

            <xsl:variable name="Descendants" select="key ('ChildNodes', Id)" />

            <xsl:if test="count ($Descendants) > 0">
                <ul>
                    <xsl:apply-templates select="$Descendants" />
                </ul>
            </xsl:if>
        </li>
    </xsl:template>
</xsl:stylesheet>

我当前的输出:

1
   1.1
   1.2
        1.2.1
   1.3
   1.4
        1.4.1
2
   2.1
   2.2
        2.2.1
3

可取的结果示例:

1
   1.1
   1.2
        1.2.1
   1.3
   1.4
2
3

1 个答案:

答案 0 :(得分:1)

这样做的一种方法是使用节点集函数,这需要在XSLT中使用扩展名称空间。

您可以做的是,而不是直接输出 Descendants 变量:

<ul>
   <xsl:apply-templates select="$Descendants"/>
</ul>

您可以将结果存储在变量

<xsl:variable name="list">
   <ul>
      <xsl:apply-templates select="$Descendants"/>
   </ul>
</xsl:variable>

然后,您可以将此“结果树片段”转换为节点集,然后您可以检查所选元素(保存在 b 元素中)是否存在。如果是,则可以输出

<xsl:if test="exsl:node-set($list)//li[b]">
   <xsl:copy-of select="$list"/>
</xsl:if>

这是完整的XSLT

<xsl:stylesheet version="1.0" 
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
 xmlns:exsl="urn:schemas-microsoft-com:xslt" 
 exclude-result-prefixes="exsl">
   <xsl:output method="html"/>
   <xsl:param name="SelectedId" select="'10'"/>
   <xsl:key name="ChildNodes" match="/Items/Item" use="ParentId"/>

   <xsl:template match="Items">
      <ul>
         <xsl:apply-templates select="Item[ParentId = 0]"/>
      </ul>
   </xsl:template>

   <xsl:template match="Item">
      <li>
         <xsl:choose>
            <xsl:when test="Id = $SelectedId">
               <b>
                  <xsl:value-of select="Name"/>
               </b>
            </xsl:when>
            <xsl:otherwise>
               <xsl:value-of select="Name"/>
            </xsl:otherwise>
         </xsl:choose>
         <xsl:variable name="Descendants" select="key ('ChildNodes', Id)"/>
         <xsl:if test="count ($Descendants) &gt; 0">
            <xsl:variable name="list">
               <ul>
                  <xsl:apply-templates select="$Descendants"/>
               </ul>
            </xsl:variable>
            <xsl:if test="exsl:node-set($list)//li[b]">
               <xsl:copy-of select="$list"/>
            </xsl:if>
         </xsl:if>
      </li>
   </xsl:template>
</xsl:stylesheet>

当应用于您的示例XML时,输出以下内容

<ul>
   <li>1
      <ul>
         <li>1.1</li>
         <li>1.2
            <ul>
               <li>
                  <b>1.2.1</b>
               </li>
            </ul></li>
         <li>1.3</li>
         <li>1.4</li>
      </ul></li>
   <li>2</li>
   <li>3</li>
</ul>

注意,因为我在这里使用Microsoft XML,扩展名称空间是“urn:schemas-microsoft-com:xslt”。对于其他处理器,您可能必须使用“http://exslt.org/common”