【问题标题】:XSLT 1.0 - Grouping complex nested elements with attributesXSLT 1.0 - 使用属性对复杂的嵌套元素进行分组
【发布时间】:2017-04-26 11:34:37
【问题描述】:

我有一个使用 XSLT 1.0 转换的 XML 文档:

<?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 Grouping 方法获得一组表达式类型(Object_Text 等)。但是我的问题是,我无法通过它们的属性@context 来区分这些表达式类型,因此容器只包含对正确表达式的分配,而它实际上包含相同的@context。

感谢您的帮助。有人知道实现所需输出的方法吗?我尝试了很多事情,但目前缺乏此任务的经验/知识。

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

【问题讨论】:

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


    【解决方案1】:

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

    <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 中查看它的实际效果。

    【讨论】:

    • 感谢您的回答,这确实帮助了我,并为我的工作提供了正确的提示!
    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-01
      • 1970-01-01
      相关资源
      最近更新 更多