使用 XSLT 将 XML 节点组合成单个节点
Posted
技术标签:
【中文标题】使用 XSLT 将 XML 节点组合成单个节点【英文标题】:Combining XML Nodes into a single node with an XSLT 【发布时间】:2019-04-11 08:41:21 【问题描述】:我正在尝试使用转换编辑一些 XML,但我正在努力实现我想要的结果。
我有一些 XML:
<FX>
<Order ATTRIBUTE1="ACTIVE" ATTRIBUTE2="CCY" />
<Attribute NAME="N1" VALUE="V1" />
<Attribute NAME="N2" VALUE="V2" />
<Attribute NAME="N3" VALUE="V3" />
</FX>
我想把它改成这样:
<FX>
<Order ATTRIBUTE1="ACTIVE" ATTRIBUTE2="CCY" />
<Attribute NAME="N1, N2, N3" VALUE="V1,V2,V3" />
</FX>
这可能吗?任何人都可以提供有关如何使用转换执行此操作的任何建议吗?
【问题讨论】:
您的 XML 无效 你为什么这么说?我只是以此为例来说明我试图实现的基本目标...... 因为它无效(在您编辑之前)。我们无法猜测 XML 的正确结构是什么 顺便说一句,您真的需要使用 XSLT 吗? Linq to XML 是一种选择吗?还是 XML 序列化/反序列化? 我正在尝试这样做以避免需要更改代码。我有适当的架构来对传入的 XML 使用转换。如果我可以通过变换实现我想要的结果,那将是一场胜利。 【参考方案1】:您可以使用以下与 Asp.NET 兼容的 XSLT-1.0 样式表来执行从源 XML 到目标 XML 的 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" omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/FX">
<xsl:copy>
<xsl:copy-of select="Order" />
<Attribute>
<xsl:attribute name="NAME">
<xsl:for-each select="Attribute">
<xsl:value-of select="@NAME" />
<xsl:if test="position() != last()">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:attribute>
<xsl:attribute name="VALUE">
<xsl:for-each select="Attribute">
<xsl:value-of select="@VALUE" />
<xsl:if test="position() != last()">
<xsl:text>,</xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:attribute>
</Attribute>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
它的输出是:
<FX>
<Order ATTRIBUTE1="ACTIVE" ATTRIBUTE2="CCY"/>
<Attribute NAME="N1, N2, N3" VALUE="V1,V2,V3"/>
</FX>
【讨论】:
谢谢!这与我需要的非常接近。目标与 XML 的外观无关,我希望它保持不变,除了删除所有重复的 ATTRIBUTE 节点并将其替换为单个 ATTRIBUTE 节点,该节点包含原始消息中的所有名称/值对,以逗号表示NAME/VALUE 的分隔属性。 感谢您的回复,这是一个很好的开始!欣赏它。 “关闭”是什么意思。结果正是您在问题中所要求的。 我几乎拆开了我实际使用的 XML,试图说明我想要发生的事情。我的实际 XML 有一堆节点(有时会出现在 XML 中,有时不会出现)。我基本上试图保持 XML 的原样,唯一的变化是操作 Attribute 节点并将它们压缩为单个节点。对不起,我应该在我的帖子中更清楚。无论如何,我非常感谢您的宝贵时间和您的回复。 我用一般来说,如果您想转换一些节点但保留其余节点,您可以使用身份转换模板作为起点,然后添加模板来更改您想要更改的那些节点:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="FX/Attribute[1]">
<xsl:copy>
<xsl:apply-templates select="@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="FX/Attribute[position() > 1]"/>
<xsl:template match="FX/Attribute[1]/@*">
<xsl:attribute name="name()">
<xsl:for-each select=". | ../following-sibling::Attribute/@*[name() = name(current())]">
<xsl:if test="position() > 1">,</xsl:if>
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/jyH9rNk
【讨论】:
非常感谢您的帮助!非常感谢您的宝贵时间!以上是关于使用 XSLT 将 XML 节点组合成单个节点的主要内容,如果未能解决你的问题,请参考以下文章
我们如何识别一组节点并将该组添加到另一个 XSLT 中 XML 源结构不同的节点?