如何在xslt中嵌套多个元素

时间:2017-06-29 12:43:26

标签: xml xslt-2.0

我有以下场景,我从未做过嵌套转换,我不知道如何开始。我有以下样本。如果该值具有两位数,则它成为所有后代的祖先。

输入:

<Items Title="Title" Icon="Icon" Description="Description">
    <Item Value="01" Name="Agriculture"/>
    <Item Value="011" Name="Horticulture and Fruit Growing"/>
    <Item Value="0111" Name="Plant Nurseries"/>
    <Item Value="011101" Name="Bulb Propagating"/>
    <Item Value="0112" Name="Cut Flower and Flower Seed Growing"/>
    <Item Value="011201" Name="Display Foliage Growing"/>

...      ......值继续

欲望输出:

<Items Title="Title" Icon="Icon" Description="Description">
    <Item Name="Agriculture">
        <Item Value="011" Name="Horticulture and Fruit Growing">
            <Item Value="0111" Name="Plant Nurseries">
                <Item Value="011101" Name="Bulb Propagating" />
            </Item>
            <Item Value="0112" Name="Cut Flower and Flower Seed Growing">
                <Item Value="011201" Name="Display Foliage Growing" />
            </Item>
        </Item>
    </Item>

...     

我使用了以下xslt:

<xsl:template match="Items">
       <Items Title="{@Title}" Icon="{@Icon}" Description="{@Description}">

           <xsl:for-each select="Item">
               <xsl:if test="string-length(@Value) = 2">
                   <Item Name="{@Name}">
                       <xsl:for-each select="ancestor::Items/Item">
                           <xsl:if test="string-length(@Value) = 3">
                               <Item Value="{@Value}" Name="{@Name}">

                               </Item>
                           </xsl:if>
                       </xsl:for-each>
                   </Item>
               </xsl:if>
           </xsl:for-each> 

       </Items>
   </xsl:template>

但这不适用于4级和6级。

现在的结果是:

<Items Title="Title" Icon="Icon" Description="Description">
<Item Name="Agriculture">
    <Item Value="011" Name="Horticulture and Fruit Growing"/>

...
    

1 个答案:

答案 0 :(得分:1)

你可以使用xsl:for-each-group group-starting-with解决这个问题,因为你想要处理几个级别,最好写一个递归函数:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:mf="http://example.com/mf"
    exclude-result-prefixes="xs mf"
    version="2.0">

    <xsl:output indent="yes"/>

    <xsl:function name="mf:group" as="element(Item)*">
        <xsl:param name="items" as="element(Item)*"/>
        <xsl:param name="level" as="xs:integer"/>
        <xsl:for-each-group select="$items" group-starting-with="Item[string-length(@Value) eq $level]">
            <xsl:choose>
                <xsl:when test="self::Item[string-length(@Value) eq $level]">
                    <xsl:copy>
                        <xsl:copy-of select="@*"/>
                        <xsl:sequence select="mf:group(current-group() except ., min((current-group() except .)/string-length(@Value)))"/>
                    </xsl:copy>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:apply-templates select="mf:group(current-group(), min(current-group()/@Value))"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each-group>
    </xsl:function>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Items">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:sequence select="mf:group(Item, 2)"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>