如何使用 xslt 1.0 根据 xml 元素的子元素值拆分分组

问题描述 投票:0回答:1

在 XSL 文档中,我需要根据其值对 image 元素进行分组:

  • 具有 size=full 的元素应该单独存在于 imageset 中。
  • 具有 size=half 的元素应该位于 imageset ...
    • 成对,如果有两个相邻的 image 元素具有 size=half
    • 单独,如果没有的话。

事实证明,这对我来说实施起来非常棘手。

对于工具,我在 .NET 4.8 软件中拥有标准 XSLT 1.0 引擎。

来源数据:

<?xml version="1.0" encoding="UTF-8" ?>
<imagecollection>
    <imageset>
        <image>
            <size>half</size>
            <id>a group 1</id>
        </image>
        <image>
            <size>half</size>
            <id>b group 1</id>
        </image>
        <image>
            <size>full</size>
            <id>c group 2</id>
        </image>
        <image>
            <size>half</size>
            <id>d group 3</id>
        </image>
        <image>
            <size>full</size>
            <id>e group 4</id>
        </image>
        <image>
            <size>full</size>
            <id>f group 5</id>
        </image>
        <image>
            <size>half</size>
            <id>g group 6</id>
        </image>
    </imageset>
</imagecollection>

我最终完成了这个转变:

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="imagecollection">
        <imagecollection>
            <xsl:for-each select="imageset/image[not(preceding-sibling::image[1][size='half'] and size='half')]">
                <imageset>
                    <xsl:copy-of select="."/>
                    <xsl:if test="following-sibling::image[1][size='half'] and size='half'">
                        <xsl:copy-of select="following-sibling::image[1]"/>
                    </xsl:if>
                </imageset>
            </xsl:for-each>
        </imagecollection>
    </xsl:template>
</xsl:stylesheet>

事实上,我使用上面的数据得到了正确的结果:

<imagecollection>
    <imageset>
        <image>
            <size>half</size>
            <id>a group 1</id>
        </image>
        <image>
            <size>half</size>
            <id>b group 1</id>
        </image>
    </imageset>
    <imageset>
        <image>
            <size>full</size>
            <id>c group 2</id>
        </image>
    </imageset>
    <imageset>
        <image>
            <size>half</size>
            <id>d group 3</id>
        </image>
    </imageset>
    <imageset>
        <image>
            <size>full</size>
            <id>e group 4</id>
        </image>
    </imageset>
    <imageset>
        <image>
            <size>full</size>
            <id>f group 5</id>
        </image>
    </imageset>
    <imageset>
        <image>
            <size>half</size>
            <id>g group 6</id>
        </image>
    </imageset>
</imagecollection>

但是转换无法处理这个简单的数据:

<?xml version="1.0" encoding="UTF-8" ?>
<imagecollection>
    <imageset>
        <image>
            <size>half</size>
            <id>a group 1</id>
        </image>
        <image>
            <size>half</size>
            <id>b group 1</id>
        </image>
        <image>
            <size>half</size>
            <id>c group 2</id>
        </image>
    </imageset>
</imagecollection>

我的转换给出了这个输出:

<imagecollection>
    <imageset>
        <image>
            <size>half</size>
            <id>a group 1</id>
        </image>
        <image>
            <size>half</size>
            <id>b group 1</id>
        </image>
    </imageset>
</imagecollection>

...所以三个 **图像 ** 元素中的最后一个丢失了。

我尝试了很多方法,但很容易破坏逻辑:一个元素是第二次出现还是完全被省略。 想知道我是否遗漏了一些简单的东西,或者是否有一种更简单的方法来处理这种分组。

xml xslt split
1个回答
0
投票

假设处理相邻半图像的每个部分的规则是按现有顺序将它们配对,只保留一组中的最后一个奇数,您可以使用称为“兄弟递归”的技术来实现它:

XSLT 1.0

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

<xsl:template match="/imagecollection">
    <imagecollection>
        <!-- start with first image -->
        <xsl:apply-templates select="imageset/image[1]"/>
    </imagecollection>
</xsl:template>

<!-- first half of pair -->
<xsl:template match="image[size='half' and following-sibling::image[1]/size='half']">
    <imageset>
        <!-- copy self and other half -->
        <xsl:copy-of select="."/>
        <xsl:copy-of select="following-sibling::image[1]"/>
    </imageset>
    <!-- skip to sibling after next -->
    <xsl:apply-templates select="following-sibling::image[2]"/>
</xsl:template>

<!-- full or standalone half -->
<xsl:template match="image">
    <imageset>
        <xsl:copy-of select="."/>
    </imageset>
    <!-- continue recursion with following sibling -->
    <xsl:apply-templates select="following-sibling::image[1]"/>
</xsl:template>

</xsl:stylesheet>
© www.soinside.com 2019 - 2024. All rights reserved.