如何使用XSLT将带分隔符的元素转换为树形结构
XSLT实现扁平XML到树形结构的转换(支持无限层级)
需要将元素名以点分隔层级的扁平XML,转换为嵌套的树形XML结构,要求至少支持2级,理想支持无限层级。
输入示例
<XML> <A.W>1</A.W> <A.X>2</A.X> <B.Y>3</B.Y> <B.Z>4</B.Z> <C>5</C> </XML>
期望输出
<XML> <A> <W>1</W> <X>2</X> </A> <B> <Y>3</Y> <Z>4</Z> </B> <C>5</C> </XML>
XSLT解决方案(支持无限层级)
以下是XSLT 2.0实现代码,通过分组和递归模板处理任意层级的点分隔元素名:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <!-- 匹配根节点,保留根元素并处理子节点 --> <xsl:template match="/*"> <xsl:copy> <!-- 按元素名的第一部分分组 --> <xsl:for-each-group select="*" group-by="tokenize(local-name(), '\.')[1]"> <!-- 创建当前层级的元素 --> <xsl:element name="{current-grouping-key()}"> <!-- 处理分组内的每个元素 --> <xsl:apply-templates select="current-group()" mode="nest"> <xsl:with-param name="prefix" select="current-grouping-key()"/> </xsl:apply-templates> </xsl:element> </xsl:for-each-group> </xsl:copy> </xsl:template> <!-- 递归处理剩余层级的模板 --> <xsl:template match="*" mode="nest"> <xsl:param name="prefix"/> <!-- 获取去掉前缀后的剩余部分 --> <xsl:variable name="remaining" select="substring-after(local-name(), concat($prefix, '.'))"/> <xsl:choose> <!-- 如果剩余部分为空,说明是叶子节点,输出文本 --> <xsl:when test="$remaining = ''"> <xsl:value-of select="."/> </xsl:when> <!-- 如果还有层级,继续分组处理 --> <xsl:otherwise> <xsl:for-each-group select="current-group()" group-by="tokenize($remaining, '\.')[1]"> <xsl:element name="{current-grouping-key()}"> <xsl:apply-templates select="current-group()" mode="nest"> <xsl:with-param name="prefix" select="concat($prefix, '.', current-grouping-key())"/> </xsl:apply-templates> </xsl:element> </xsl:for-each-group> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet>
代码说明
- 根节点模板:匹配输入的根元素(如
<XML>),保留根元素后,将所有子元素按元素名的第一个点分隔段分组,创建对应层级的父元素。 - 递归嵌套模板:
- 接收当前处理的前缀参数,计算去掉前缀后的剩余元素名部分。
- 如果剩余部分为空,直接输出元素的文本内容(叶子节点)。
- 如果剩余部分还有点分隔的层级,继续分组并递归创建下一层元素,直到处理完所有层级。
这个方案支持任意深度的点分隔元素名,比如A.B.C.D这类多层级元素也能正确转换为嵌套结构。
内容的提问来源于stack exchange,提问作者Peter
相关产品推荐
相关产品推荐

