我有一个xml输入,其中包含一个xml子节点列表。我想基于xml子节点分离这个xml。但是在分离时,需要保留父节点。我尝试使用for-each,但输出并不像预期的那样。
输入
<node1>
<id>1</id>
<code>abcd</code>
<version>v1</version>
<node2>
<market>india</market>
<active>true</active>
</node2>
<node2>
<market>US</market>
<active>true</active>
</node2>
<mixins>
<node3>
<ref>MZ-SR-P004</ref>
<type>Commercial</type>
</node3>
</mixins>
</node1>
预期产出
<node1>
<id>1</id>
<code>abcd</code>
<version>v1</version>
<node2>
<market>india</market>
<active>true</active>
</node2>
<mixins>
<node3>
<ref>MZ-SR-P004</ref>
<type>Commercial</type>
</node3>
</mixins>
</node1>
<node1>
<id>1</id>
<code>abcd</code>
<version>v1</version>
<node2>
<market>US</market>
<active>true</active>
</node2>
<mixins>
<node3>
<ref>MZ-SR-P004</ref>
<type>Commercial</type>
</node3>
</mixins>
</node1>
是否可以使用xslt来完成它。我尝试了下面的XSLT转换
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"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
<xsl:apply-templates />
</xsl:template>
<xsl:template match="node2">
<xsl:for-each select="node2">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
我目前的输出如下所示
当前的xml输出
<?xml version="1.0" encoding="UTF-8"?>
<node1>
<id>1</id>
1
<code>abcd</code>
abcd
<version>v1</version>
v1
<mixins>
<node3>
<ref>MZ-SR-P004</ref>
MZ-SR-P004
<type>Commercial</type>
Commercial
</node3>
<ref>MZ-SR-P004</ref>
MZ-SR-P004
<type>Commercial</type>
Commercial
</mixins>
<node3>
<ref>MZ-SR-P004</ref>
MZ-SR-P004
<type>Commercial</type>
Commercial
</node3>
<ref>MZ-SR-P004</ref>
MZ-SR-P004
<type>Commercial</type>
Commercial
</node1>
<id>1</id>1
<code>abcd</code>abcd
<version>v1</version>v1
<mixins>
<node3>
<ref>MZ-SR-P004</ref>MZ-SR-P004
<type>Commercial</type>Commercial
</node3>
<ref>MZ-SR-P004</ref>MZ-SR-P004
<type>Commercial</type>Commercial
</mixins>
<node3>
<ref>MZ-SR-P004</ref>MZ-SR-P004
<type>Commercial</type>Commercial
</node3>
<ref>MZ-SR-P004</ref>MZ-SR-P004
<type>Commercial</type>Commercial
在你的模板匹配node2
然后你做一个xsl:for-each
选择node2
,但那将寻找你匹配的当前node2
的子元素,所以没有任何选择。
你的模板应该选择node1
。然后,在xsl:for-each
中,您需要创建node1
并复制所有子节点,这些子节点是当前的node2
或不同名称的节点
试试这个XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="node1">
<xsl:for-each select="node2">
<node1>
<xsl:apply-templates select="../*[generate-id() = generate-id(current()) or not(self::node2)]" />
</node1>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
注意我还从身份模板中删除了<xsl:apply-templates />
。
一个更通用的XSLT 2或3方法是选择节点(例如node1/node2
),然后通过一个模式推送完整的树,使用存储当前node2
的隧道参数进行身份复制,以确保该模式何时匹配node2
输出这个特殊的node2
并忽略所有其他:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:mode name="reconstruct" on-no-match="shallow-copy"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:for-each select="node1/node2">
<xsl:apply-templates select="/" mode="reconstruct">
<xsl:with-param name="copy" tunnel="yes" select="current()"/>
</xsl:apply-templates>
</xsl:for-each>
</xsl:template>
<xsl:template match="node2" mode="reconstruct">
<xsl:param name="copy" tunnel="yes"/>
<xsl:sequence select=".[. is $copy]"/>
</xsl:template>
</xsl:stylesheet>