XSLT 1.0 - 使用属性对复杂的嵌套元素进行分组

XSLT 1.0 - Grouping complex nested elements with attributes

我有一个 XML 文档,我用 XSLT 1.0 对其进行了转换:

<?xml version="1.0" encoding="UTF-8"?>
<element tag="container">
    <data handle="">
        ...
    </data>
    <assignments/>
    <expression context="">
        Object_Text
    </expression>
    <expression context="">
        Object_Text
    </expression>
    <expression context="">
        Object_Heading
    </expression>   
    <element tag="container">
        <data handle="">
            ...
        </data>
        <assignments/>
        <element tag="container">
            <data handle="">
                ...
            </data>
            <assignments/>
            <expression context="">
                Object_Text
            </expression>
        </element>
        <element tag="container">
            ...
        </element>
    </element>
    <element tag="container">
        <element tag="container">
            <element tag="container">
                <expression context="">
                    Object_Text
                </expression>
            </element>
        </element>  
    </element>
    <element tag="container">
    <expression context="">
        Object_Identifier
    </expression>   
    </element>
</element>

我必须将每个表达式类型(Object_Text、Object_Heading、...)的赋值添加到下一个 parent 容器节点的标记中包含一个标签(不是所有容器都有那个标签,那些应该被忽略)并且表达式的上下文值必须符合容器的句柄值。因为我需要为每种表达式类型赋值,所以无论它出现多少,我都应该在其上下文中为每种类型赋值。所以期望的输出是:

<?xml version="1.0" encoding="UTF-8"?>
<element tag="container">
    <data handle="">
        ...
    </data>
    <assignments> <!--Added assignments here (one for each type with @context='')-->
        <assignment name="Object_Text">
        </assignment>
        <assignment name="Object_Heading">
        </assignment>
        <assignment name="Object_Identifier">
        </assignment>
    </assignments>
    <expression context="">
        Object_Text
    </expression>
    <expression context="">
        Object_Text
    </expression>
    <expression context="">
        Object_Heading
    </expression>   
    <element tag="container">
        <data handle="">
            ...
        </data>
        <assignments/>
        <element tag="container">
            <data handle="">
                ...
            </data>
            <assignments> <!--Added assignments here (one for each type with @context='')-->
                <assignment name="Object_Text">
                </assignment>
            </assignments>
            <expression context="">
                Object_Text
            </expression>
        </element>
        <element tag="container">
            ...
        </element>
    </element>

    <element tag="container">
    <expression context="">
        Object_Identifier
    </expression>   
    </element>
</element>

目前我可以用Muenchian Grouping方法得到一组表达类型(Object_Text等)。但我的问题是,我无法通过它们的属性 @context 来区分这些表达式类型,因此容器只包含对正确表达式的赋值,它实际上包含相同的 @context。

我很感激任何帮助。有人知道实现所需输出的方法吗?我已经尝试了很多东西,但目前缺少 experience/knowledge 来完成这项任务。

编辑:应该补充的是,这是 xml 文档的示例结构。所以 xslt 函数应该可以识别任意嵌套、包装结构和任意次数的表达式。

这会让你继续前进。您正在进行一些抑制,此代码没有说明。

  <!-- Handle each container that has an assignments node. -->
  <xsl:template match="element[@tag='container' and .//assignments]">
    <!-- Bind to the expressions for this container. -->
    <xsl:variable name="expressions" select="expression"/>
    <xsl:copy>
      <xsl:apply-templates select="node()|@*">
        <xsl:with-param name="expressions" select="$expressions"/>
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>

  <!-- Create the assignments for each container. -->
  <xsl:template match="assignments">
    <xsl:param name="expressions"/>
    <xsl:copy>
      <xsl:for-each select="$expressions">
        <xsl:element name="assignment">
          <xsl:attribute name="name">
            <xsl:value-of select="normalize-space(.)"/>
          </xsl:attribute>
        </xsl:element>
      </xsl:for-each>
    </xsl:copy>
  </xsl:template>

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

让我们从为表达式声明一个键开始

<xsl:key name="kExp" match="expression" use="concat(@context, '|', normalize-space(.))"/>

assignments节点下,我们将放置第一个前置兄弟节点data

@handle属性
<xsl:variable name="dataHandle" select="preceding-sibling::data/@handle"/>

当这个变量用于 assignments 节点并使用 Muenchian 方法时(我假设表达式是 assignments 节点的兄弟姐妹或兄弟姐妹的后代):

    <xsl:template match="assignments">
        <xsl:variable name="dataHandle" select="preceding-sibling::data/@handle"/>
        <xsl:copy>
            <xsl:for-each select="../descendant::expression[@context=$dataHandle 
                                  and generate-id()=generate-id(key('kExp', concat(@context, '|', normalize-space(.)))[1])]">
                <assignment name="{normalize-space(.)}"></assignment>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>

整个样式表如下:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:strip-space elements="*"/>
    <xsl:output indent="yes"/>

    <xsl:key name="kExp" match="expression" use="concat(@context, '|', normalize-space(.))"/>


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

    <xsl:template match="assignments">
        <xsl:variable name="dataHandle" select="preceding-sibling::data/@handle"/>
        <xsl:copy>
            <xsl:for-each select="../descendant::expression[@context=$dataHandle 
                                  and generate-id()=generate-id(key('kExp', concat(@context, '|', normalize-space(.)))[1])]">
                <assignment name="{normalize-space(.)}"></assignment>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

http://xsltransform.net/a9Giwr 中查看实际效果。