XSLT 2.0组节点集检查后代属性

时间:2016-02-01 16:10:30

标签: xslt-2.0

我有以下节点集片段:

<category value="Library">
    <category value="PACS">
        <category value="IMPAX (PACS)">
               <category value="Reporting"/>
        </category>
    </category>
</category>
<category value="Library">
    <category value="Enterprise Imaging">
        <category value="Desktops"/>
    </category>
</category>
<category value="Library">
    <category value="PACS">
        <category value="IMPAX (PACS)"/>
    </category>
</category>

由以下内容生成:

<xsl:template name="categories">
<xsl:param name="topicmeta"/>
<xsl:variable name="VarCategories">

        <xsl:for-each select="map/topicmeta/category">
            <xsl:if test="contains(./data/@value, 'Library')">
                <xsl:if
                    test="string-length(./data/@value) - string-length(translate(./data/@value, '/', '')) &gt; 1">

                    <xsl:call-template name="category">
                        <xsl:with-param name="category" select="./data/@value"/>
                    </xsl:call-template>

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

    </xsl:variable>

    <xsl:call-template name="outputCategories">
        <xsl:with-param name="categories" select="$VarCategories"/>
    </xsl:call-template>
</xsl:template>   

我需要输出:

<category value="Library">
    <category value="PACS">
        <category value="IMPAX (PACS)">
               <category value="Reporting"/>
        </category>
    </category>
    <category value="Enterprise Imaging">
        <category value="Desktops"/>
    </category>
</category>

我正在尝试使用for-each-group

<xsl:template name="outputCategories">
    <xsl:param name="categories"/>
    <xsl:element name="categories">
     <xsl:for-each-group select="$categories/*" group-adjacent="@value">
         <xsl:sort select="@value"></xsl:sort>
         <xsl:copy-of select="." />
     </xsl:for-each-group>
    </xsl:element>
</xsl:template>

这给了我:

<category value="Library">
  <category value="PACS">
     <category value="IMPAX (PACS)">
        <category value="Reporting"/>
     </category>
  </category>

我需要检查每个级别并对每个不同的值进行分组。

1 个答案:

答案 0 :(得分:0)

将代码放入递归函数中:

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

    <xsl:output indent="yes"/>

    <xsl:function name="mf:group" as="element(category)*">
        <xsl:param name="categories" as="element(category)*"/>
        <xsl:for-each-group select="$categories" group-by="@value">
            <category value="{current-grouping-key()}">
                <xsl:sequence select="mf:group(current-group()/category)"/>
            </category>
        </xsl:for-each-group>
    </xsl:function>

    <xsl:param name="cats">
        <category value="Library">
    <category value="PACS">
        <category value="IMPAX (PACS)">
               <category value="Reporting"/>
        </category>
    </category>
</category>
<category value="Library">
    <category value="Enterprise Imaging">
        <category value="Desktops"/>
    </category>
</category>
<category value="Library">
    <category value="PACS">
        <category value="IMPAX (PACS)"/>
    </category>
</category>
    </xsl:param>

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

    <xsl:template match="/">
        <xsl:sequence select="mf:group($cats/category)"/>
    </xsl:template>
</xsl:transform>

http://xsltransform.net/3NJ38ZB在线。

如果您还需要排序,请将功能更改为例如

<xsl:function name="mf:group" as="element(category)*">
    <xsl:param name="categories" as="element(category)*"/>
    <xsl:for-each-group select="$categories" group-by="@value">
        <xsl:sort select="current-grouping-key()"/>
        <category value="{current-grouping-key()}">
            <xsl:sequence select="mf:group(current-group()/category)"/>
        </category>
    </xsl:for-each-group>
</xsl:function>

对于您在评论中链接的示例,它将其创建的category元素放在FO命名空间中,您必须通过执行

来避免这种情况
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns="http://www.w3.org/1999/XSL/Format"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:exsl="http://exslt.org/common"
    xmlns:mf="http://example.com/mf"
    exclude-result-prefixes="xs exsl mf">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>
    <xsl:param name="status"/>    
    <xsl:param name="draft"/>
    <xsl:template match="/">
        <index>


            <xsl:call-template name="categories"> </xsl:call-template>

        </index>
    </xsl:template>

    <xsl:template name="categories">
        <xsl:param name="topicmeta"/>
        <xsl:variable name="VarCategories">

                <xsl:for-each select="map/topicmeta/category">
                    <xsl:if test="contains(./data/@value, 'Library')">
                        <xsl:if
                            test="string-length(./data/@value) - string-length(translate(./data/@value, '/', '')) &gt; 1">

                            <xsl:call-template name="category">
                                <xsl:with-param name="category" select="./data/@value"/>
                            </xsl:call-template>

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

        </xsl:variable>

        <xsl:sequence select="mf:group($VarCategories/category)"/>


    </xsl:template>

    <xsl:template name="category" xmlns="">
        <xsl:param name="category"/>
        <xsl:if test="string-length($category) &gt; 0">
            <xsl:element name="category">
                <xsl:attribute name="value">
                    <xsl:choose>
                        <xsl:when test="substring-before($category, '/') = ''">
                            <xsl:value-of select="$category"/>
                        </xsl:when>
                        <xsl:otherwise>
                            <xsl:value-of select="substring-before($category, '/')"/>
                        </xsl:otherwise>
                    </xsl:choose>
                </xsl:attribute>

                <xsl:call-template name="category">
                    <xsl:with-param name="category" select="substring-after($category, '/')"/>
                </xsl:call-template>
            </xsl:element>
        </xsl:if>
    </xsl:template>

<xsl:function name="mf:group" as="element(category)*" xmlns="">
    <xsl:param name="categories" as="element(category)*"/>
    <xsl:for-each-group select="$categories" group-by="@value">
        <xsl:sort select="current-grouping-key()"/>
        <category value="{current-grouping-key()}">
            <xsl:sequence select="mf:group(current-group()/category)"/>
        </category>
    </xsl:for-each-group>
</xsl:function>


</xsl:stylesheet>

或者您必须确保函数中的路径选择该命名空间中的元素:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns="http://www.w3.org/1999/XSL/Format"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:exsl="http://exslt.org/common"
    xmlns:mf="http://example.com/mf"
    exclude-result-prefixes="xs exsl mf">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>
    <xsl:param name="status"/>    
    <xsl:param name="draft"/>
    <xsl:template match="/">
        <index>


            <xsl:call-template name="categories"> </xsl:call-template>

        </index>
    </xsl:template>

    <xsl:template name="categories">
        <xsl:param name="topicmeta"/>
        <xsl:variable name="VarCategories">

                <xsl:for-each select="map/topicmeta/category">
                    <xsl:if test="contains(./data/@value, 'Library')">
                        <xsl:if
                            test="string-length(./data/@value) - string-length(translate(./data/@value, '/', '')) &gt; 1">

                            <xsl:call-template name="category">
                                <xsl:with-param name="category" select="./data/@value"/>
                            </xsl:call-template>

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

        </xsl:variable>

        <xsl:sequence select="mf:group($VarCategories/*)"/>


    </xsl:template>

    <xsl:template name="category">
        <xsl:param name="category"/>
        <xsl:if test="string-length($category) &gt; 0">
            <xsl:element name="category">
                <xsl:attribute name="value">
                    <xsl:choose>
                        <xsl:when test="substring-before($category, '/') = ''">
                            <xsl:value-of select="$category"/>
                        </xsl:when>
                        <xsl:otherwise>
                            <xsl:value-of select="substring-before($category, '/')"/>
                        </xsl:otherwise>
                    </xsl:choose>
                </xsl:attribute>

                <xsl:call-template name="category">
                    <xsl:with-param name="category" select="substring-after($category, '/')"/>
                </xsl:call-template>
            </xsl:element>
        </xsl:if>
    </xsl:template>

<xsl:function name="mf:group" as="element(category)*" xpath-default-namespace="http://www.w3.org/1999/XSL/Format">
    <xsl:param name="categories" as="element(category)*"/>
    <xsl:for-each-group select="$categories" group-by="@value">
        <xsl:sort select="current-grouping-key()"/>
        <category value="{current-grouping-key()}">
            <xsl:sequence select="mf:group(current-group()/category)"/>
        </category>
    </xsl:for-each-group>
</xsl:function>


</xsl:stylesheet>