递归连接父属性 [英] Concatenate parent attributes recursively
问题描述
给定以下 XML:
<package>
<node name="a">
<node name="b"/>
<node name="c"/>
<node name="d">
<node name="e"/>
<node name="f"/>
<node name="g">
<node name="h"/>
</node>
</node>
</node>
</package>
我基本上想在连接每个父 node
元素的 name
属性的同时压平树,直到最后一个 node
元素:
I basically want to flatten the tree while concatenating the name
attributes of each parent node
element until the last node
element:
<package>
<node name="a-b"/>
<node name="a-c"/>
<node name="a-d-e"/>
<node name="a-d-f"/>
<node name="a-d-g-h"/>
</package>
到目前为止我所做的是使用模板和 xsl:copy-of
正确生成所有 node
元素的平面列表:
What I got working so far is is properly generating a flat list of all node
elements using a template and xsl:copy-of
:
<xsl:template match="//node">
<xsl:copy-of select="current()"/>
</xsl:template>
这给了我:
<package>
<node name="b"/>
<node name="c"/>
<node name="e"/>
<node name="f"/>
<node name="h"/>
</package>
但我不确定如何正确地从这里继续.我的目的是扩展模板并使用 xsl:attribute
和 xsl:for-each
来连接和修改属性:
But I'm not sure how to properly continue from here. My intention was to extend the template and using xsl:attribute
and xsl:for-each
to concatenate and modify the attribute:
<xsl:template match="node/@name">
<xsl:attribute name="name">
<xsl:for-each select="ancestor::node">
<xsl:if test="position() > 1">.</xsl:if>
<xsl:value-of select="@name"/>
</xsl:for-each>
</xsl:attribute>
</xsl:template>
然而,这只会打印 node
的数据(如果有的话).我在这里错过了什么?
However, this only prints the node
's data (if any).
What am I missing here?
我有可用的 XSLT 2.0,我的灵感来自于这个 SO 问题.
I have XSLT 2.0 available and I got my inspiration from this SO question.
推荐答案
我基本上想在连接名称的同时展平树每个父节点元素的属性,直到最后一个节点元素:
I basically want to flatten the tree while concatenating the name attributes of each parent node element until the last node element:
这是一个完整且有效的 XSLT 2.0 解决方案:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="node[*]"><xsl:apply-templates/></xsl:template>
<xsl:template match="node[not(*)]/@name">
<xsl:attribute name="name" select="string-join(../ancestor-or-self::node/@name, '-')"/>
</xsl:template>
</xsl:stylesheet>
当此转换应用于提供的 XML 文档时:
<package>
<node name="a">
<node name="b"/>
<node name="c"/>
<node name="d">
<node name="e"/>
<node name="f"/>
<node name="g">
<node name="h"/>
</node>
</node>
</node>
</package>
产生想要的、正确的结果:
<package>
<node name="a-b"/>
<node name="a-c"/>
<node name="a-d-e"/>
<node name="a-d-f"/>
<node name="a-d-g-h"/>
</package>
<小时>
二.XSLT 1.0 解决方案:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="node[*]"><xsl:apply-templates/></xsl:template>
<xsl:template match="node[not(*)]/@name">
<xsl:attribute name="name"><xsl:apply-templates select="." mode="gen"/></xsl:attribute>
</xsl:template>
<xsl:template match="node/@name" mode="gen">
<xsl:apply-templates select="../parent::node/@name" mode="gen"/>
<xsl:if test="../parent::node">-</xsl:if>
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
在同一个 XML 文档(上图)上应用此转换时,会产生相同的正确结果:
<package>
<node name="a-b"/>
<node name="a-c"/>
<node name="a-d-e"/>
<node name="a-d-f"/>
<node name="a-d-g-h"/>
</package>
这篇关于递归连接父属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!