[英]Merge 2 XML files (including node attributes) based on attribute values using XSLT
Note: this is NOT a duplicate of Merge 2 XML files based on attribute values using XSLT?注意:这不是使用 XSLT 基于属性值的Merge 2 XML 文件的副本吗? but an extension to it.
但它的扩展。 Given the following input files
鉴于以下输入文件
file1.xml文件1.xml
<config>
<state version="10">
<root value="100" group="5">
<leaf number = "2"/>
</root>
<root value="101" group="6" overrideAttr="oldval">
<leaf number = "3"/>
</root>
</state>
</config>
file2.xml文件2.xml
<config>
<state version="10">
<root value="100" group="5">
<leaf number = "6"/>
</root>
<root value="101" group="6" overrideAttr="newval" addtionalAttr="hello">
<leaf number = "4"/>
</root>
</state>
</config>
I'd like to have this output.xml我想要这个 output.xml
<config>
<state version="10">
<root value="100" group="5">
<leaf number = "2"/>
<leaf number = "6"/>
</root>
<root value="101" group="6" overrideAttr="newval" addtionalAttr="hello">
<leaf number = "3"/>
<leaf number = "4"/>
</root>
</state>
</config>
Desired extensions are所需的扩展是
Can this be achieved by xsl?这可以通过xsl实现吗?
In the answer that you have linked to, there is an xsl:apply-templates
that copies across the child elements from the second file.在您链接到的答案中,有一个
xsl:apply-templates
复制第二个文件中的子元素。
<xsl:apply-templates
select="document('file2.xml')
/config/state[@version = current()/../@version]
/root[@value = current()/@value and
@group = current()/@group]/*" />
All you need to do is add a similar line to copy across attributes您需要做的就是添加一个类似的行来跨属性复制
<xsl:apply-templates
select="document('file2.xml')
/config/state[@version = current()/../@version]
/root[@value = current()/@value and
@group = current()/@group]/@*" />
Although this would need to done before the copying of any existing child nodes (as attributes must be added before child nodes).尽管这需要在复制任何现有子节点之前完成(因为必须在子节点之前添加属性)。
Additionally, you might want to use a variable to avoid repeating the xpath expression.此外,您可能希望使用变量来避免重复 xpath 表达式。
Try this XSLT...试试这个 XSLT...
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="root">
<xsl:variable name="file2root" select="document('file2.xml')
/config/state[@version = current()/../@version]
/root[@value = current()/@value and
@group = current()/@group]" />
<xsl:copy>
<xsl:apply-templates select="@*" />
<xsl:apply-templates select="$file2root/@*" />
<xsl:apply-templates select="node()" />
<xsl:apply-templates select="$file2root/*" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Note that this takes advantage of the fact that " Adding an attribute to an element replaces any existing attribute of that element with the same expanded-name ".请注意,这利用了“向元素添加属性会用相同的扩展名替换该元素的任何现有属性”这一事实。 (See https://www.w3.org/TR/xslt#creating-attributes )
(见https://www.w3.org/TR/xslt#creating-attributes )
If you want to extend that solution then you can do it as follows, change that template for the root
elements ( http://xsltransform.net/gWEamLR/1 ) to如果您想扩展该解决方案,那么您可以按如下方式进行,将
root
元素的模板( http://xsltransform.net/gWEamLR/1 )更改为
<xsl:template match="root">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="$doc2
/config/state[@version = current()/../@version]
/root[@value = current()/@value and
@group = current()/@group]/@*" />
<xsl:apply-templates select="node()"/>
<xsl:apply-templates select="
$doc2
/config/state[@version = current()/../@version]
/root[@value = current()/@value and
@group = current()/@group]/*" />
</xsl:copy>
</xsl:template>
and make sure you define <xsl:param name="doc2" select="document('file2.xml')"/>
.并确保您定义了
<xsl:param name="doc2" select="document('file2.xml')"/>
。
There might be better ways using keys or grouping doing that merging, and of course in XSLT 3.0 we now have xsl:merge
使用键或分组进行合并可能有更好的方法,当然在 XSLT 3.0 中我们现在有了
xsl:merge
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:math="http://www.w3.org/2005/xpath-functions/math" exclude-result-prefixes="xs math"
version="3.0">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/" name="main">
<config>
<xsl:merge>
<xsl:merge-source select="doc('file1.xml')/config/state">
<xsl:merge-key select="@version"/>
</xsl:merge-source>
<xsl:merge-source select="doc('file2.xml')/config/state">
<xsl:merge-key select="@version"/>
</xsl:merge-source>
<xsl:merge-action>
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:merge>
<xsl:merge-source select="current-merge-group()[1]/root">
<xsl:merge-key select="@value"/>
<xsl:merge-key select="@group"/>
</xsl:merge-source>
<xsl:merge-source select="current-merge-group()[2]/root">
<xsl:merge-key select="@value"/>
<xsl:merge-key select="@group"/>
</xsl:merge-source>
<xsl:merge-action>
<xsl:copy>
<xsl:copy-of select="current-merge-group()[2]/@*"/>
<xsl:copy-of select="current-merge-group()/node()"/>
</xsl:copy>
</xsl:merge-action>
</xsl:merge>
</xsl:copy>
</xsl:merge-action>
</xsl:merge>
</config>
</xsl:template>
</xsl:stylesheet>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.