XSLT元素转属性问题:仅返回列表最后一个元素作为父节点属性
XSLT 仅转换最后一个子元素为父节点属性的问题解决
我帮你梳理下这个问题哈——你想把<Profile>的子元素都转成它的属性,但现有代码只处理了最后一个,大概率是循环逻辑里的属性覆盖问题,下面一步步给你解决:
问题场景
先看你提供的XML示例(补全了省略的部分以便展示):
<?xml version="1.0" encoding="UTF-8"?> <NB xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="file:///C:/Users/xXXXXXX/Documents/xxxxx%20Profile%20XML/Untitled13.xsd"> <Profile> <PName>165370 - XXX - XXXXXX</PName> <OrderID>165370</OrderID> <Status>I</Status> </Profile> </NB>
常见错误原因
你之前的代码大概率犯了这两个错误之一:
- 循环生成属性时,没有正确遍历所有子元素,只定位到了
last()节点; - 虽然遍历了,但属性生成逻辑有问题,后面的属性覆盖了前面的(比如错误地重复使用同一个属性名,或者模板逻辑没走对)。
举个典型的错误写法:
<xsl:template match="Profile"> <Profile> <!-- 错误:只取最后一个子元素的值生成属性 --> <xsl:attribute name="attr"> <xsl:value-of select="*[last()]"/> </xsl:attribute> </Profile> </xsl:template>
正确解决方案
要把所有子元素都转成父节点的属性,核心是遍历每个子元素,为每个子元素单独创建对应名称的属性。下面是可用的XSLT代码:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <!-- 复制除Profile外的其他节点 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 专门处理Profile节点,将其子元素转为属性 --> <xsl:template match="Profile"> <Profile> <!-- 遍历所有子元素,用子元素的本地名作为属性名,值为子元素的文本 --> <xsl:for-each select="*"> <xsl:attribute name="{local-name()}"> <xsl:value-of select="."/> </xsl:attribute> </xsl:for-each> </Profile> </xsl:template> </xsl:stylesheet>
转换效果
用这段代码处理你的XML,会得到如下输出:
<?xml version="1.0" encoding="UTF-8"?> <NB xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="file:///C:/Users/xXXXXXX/Documents/xxxxx%20Profile%20XML/Untitled13.xsd"> <Profile PName="165370 - XXX - XXXXXX" OrderID="165370" Status="I"/> </NB>
如果你只需要转换特定的子元素(不是全部),只需要修改xsl:for-each的select条件,比如select="PName|OrderID",就能只把这两个子元素转成属性。
内容的提问来源于stack exchange,提问作者GLarose
相关产品推荐
相关产品推荐

