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 中查看实际效果。
我有一个 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 中查看实际效果。