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

时间:2017-04-26 11:34:38

标签: xslt xpath xslt-1.0 nested-forms xslt-grouping

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

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

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

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

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

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

我很感激任何帮助。有人知道实现所需输出的方法吗?我尝试了很多东西,但目前缺乏这方面的经验/知识。

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

2 个答案:

答案 0 :(得分:0)

这会让你前进。你有一些抑制,这段代码没有考虑到。

  <!-- 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>

答案 1 :(得分:0)

让我们首先声明表达式的键

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

assignments节点下,我们将放置第一个前兄弟节点@handle的{​​{1}}属性

data

<xsl:variable name="dataHandle" select="preceding-sibling::data/@handle"/> 节点中使用此变量并使用Muenchian方法(我假设表达式是assignments node 的兄弟节点的兄弟或后代)时:

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>

http://xsltransform.net/a9Giwr中查看它。