xslt 2.0 / xpath-按属性分组

时间:2019-05-15 19:49:06

标签: xml xslt xpath

我有一个XML文档,我需要根据指定的属性值对相邻元素进行嵌套/分组。我知道可以根据元素类型或名称来完成此操作,但是我不确定如何使用给定的属性值来执行此操作。样本输入:

<root>
    <group>
        <p id="111">5tw5t5et</p>
        <p id="111">4qvtq3</p>
    </group>
    <p id="222">qv34tqv3</p>
    <j>qv43tvq</j>
    <group>
        <p id="333">qv43tvq</p>
        <p id="333">q34tvq43tvq</p>
        <p id="333">q3434t3tvq43tvq</p>
    </group>
</root>

所需的输出:

            <xsl:for-each-group select="*" group-adjacent="name()">
            <xsl:choose>
                <xsl:when test="name()='111'"> 
                  <group>
                    <xsl:for-each select="current-group()">
                        <xsl:apply-templates/>
                    </xsl:for-each>
                  </group>
                </xsl:when>     
                 <xsl:when test="name()='333'"> 
                  <group>
                    <xsl:for-each select="current-group()">
                        <xsl:apply-templates/>
                    </xsl:for-each>
                  </group>
                </xsl:when>             
                <xsl:otherwise>
                    <xsl:apply-templates select="current-group()"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each-group>

我知道我可以使用此元素按名称分组

<xsl:for-each-group select="*" group-adjacent="@id">

但是我不确定要使用哪种语法对属性进行分组

我已经尝试过了:

<xsl:for-each-group select="p" group-adjacent="@id">

哪个会抛出空序列错误,并且:

con = subprocess.Popen(['ssh', node, command], 
                       stdout=subprocess.PIPE, 
                       stderr=subprocess.STDOUT,  # <-- redirect stderr to stdout
                       bufsize=1)

忽略所有非p元素。

使用属性值将这些元素分组的正确方法是什么?

1 个答案:

答案 0 :(得分:1)

xsl:for-each-group的{​​{1}}不接受空的group-adjacent,因此您必须分别处理没有current-grouping-key()属性的元素。可以使用@id这样的if-then-else表达式来实现,甚至可以使用if (@id) then @id else ''来简化(由于注释)。

因此您可以像这样更改string(@id)

xsl:for-each-group

这假定已设置身份模板以复制元素和属性。

编辑:合并了注释中建议的改进。

其输出为:

<xsl:for-each-group select="*" group-adjacent="string(@id)">
    <xsl:choose>
        <xsl:when test="@id='111' or @id='333'"> 
            <group>
                <xsl:apply-templates select="current-group()"/>
            </group>
        </xsl:when>
        <xsl:otherwise>
            <xsl:apply-templates select="current-group()"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:for-each-group>