如何使用XSLT将XML子节点转为与父节点同级的同名节点
需求说明
需将所有子元素转换为与父节点层级、名称一致的节点,生成的新元素必须包含子元素的全部属性,同时保留父元素的原有属性。
源XML
<?xml version="1.0" encoding="UTF-8"?> <entry> <line id="001" att1="aaa" att2="bbb" att3="ccc"/> <line id="002" att1="ddd" att2="eee" att3="fff"/> <line id="003" att1="ggg" att2="hhh" att3="iii"> <subline x="name" z="lastname"/> <subline x="name2" z="lastname2"/> <underline a="bar" b="foo"/> </line> </entry>
预期输出
<entry> <line id="001" att1="aaa" att2="bbb" att3="ccc"/> <!-- x和z属性值可为空 --> <line id="002" att1="ddd" att2="eee" att3="fff"/> <!-- x和z属性值可为空 --> <line id="003" att1="ggg" att2="hhh" att3="iii" x="name" z="lastname"/> <line id="003" att1="ggg" att2="hhh" att3="iii" x="name2" z="lastname2"/> <line id="003" att1="ggg" att2="hhh" att3="iii" a="bar" b="foo"/> </entry>
修正后可实现需求的XSLT代码(兼容XSLT 1.0)
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"> <xsl:output method="xml" indent="yes"/> <!-- 匹配没有子元素的line节点,直接原样输出 --> <xsl:template match="line[not(*)]"> <xsl:copy> <xsl:copy-of select="@*"/> </xsl:copy> </xsl:template> <!-- 匹配有子元素的line节点,遍历所有子元素生成对应line节点 --> <xsl:template match="line[*]"> <xsl:for-each select="*"> <line> <!-- 复制父line的全部属性 --> <xsl:copy-of select="../@*"/> <!-- 复制当前子元素的全部属性 --> <xsl:copy-of select="@*"/> </line> </xsl:for-each> </xsl:template> <!-- 恒等转换模板 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
代码逻辑说明
- 对没有子节点的line节点直接拷贝输出,符合无子元素时属性无需新增的要求
- 对包含子节点的line节点,遍历每一个子元素,每个子元素对应生成一个新的line节点
- 新生成的line节点先复制父line的所有原有属性,再复制当前子元素的所有属性,完全符合需求要求
- 无需单独写模板删除子元素,因为遍历子元素时不会输出子节点本身,父line也不会单独输出,自动实现原有层级的转换
内容的提问来源于stack exchange,提问作者XSLT-explorer
相关产品推荐
相关产品推荐

