我需要合并两个相似的xml文件,但只包含与常用标记匹配的记录,例如以下示例中的<type>
:
file1.xml是
<node>
<type>a</type>
<name>joe</name>
</node>
<node>
<type>b</type>
<name>sam</name>
</node>
file2.xml是
<node>
<type>a</type>
<name>jill</name>
</node>
这样我的输出
<node>
<type>a</type>
<name>jill</name>
<name>joe</name>
</node>
<node>
<type>b</type>
<name>sam</name>
</node>
在xsl中执行此操作的基础是什么? 非常感谢。
答案 0 :(得分:5)
此样式表:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="kElementByType" match="*[not(self::type)]" use="../type"/>
<xsl:param name="pSource2" select="'file2.xml'"/>
<xsl:variable name="vSource2" select="document($pSource2,/)"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="type">
<xsl:variable name="vCurrent" select="."/>
<xsl:call-template name="identity"/>
<xsl:for-each select="$vSource2">
<xsl:apply-templates select="key('kElementByType',$vCurrent)"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
使用此输入(格式良好):
<root>
<node>
<type>a</type>
<name>joe</name>
</node>
<node>
<type>b</type>
<name>sam</name>
</node>
</root>
输出:
<root>
<node>
<type>a</type>
<name>jill</name>
<name>joe</name>
</node>
<node>
<type>b</type>
<name>sam</name>
</node>
</root>
答案 1 :(得分:1)
我认为值得添加一些我在学习时学到的额外信息,以防任何其他初学者使用。我已经更改了我的测试代码名称,因此它们不会与xsl中使用的某些术语混淆。我不知道它是最好还是最有效的做事方式,但它有效(有一些警告!)。
我想保留“info”节点,原始代码丢失了。编码单独的匹配模板会将其保留在输出中。此外,我编写它的方式,只有在节点位于输入文件(x1)中时才保留该节点。如果它在(x2)文件中,则不会保留。这必须与我编写迭代的方式一致。理想情况下,我想保留它来自任何一个输入文件,但还没有找到如何做到这一点。此外,我想通过msxsl选择将文件名x2作为参数传递,而不是硬编码。肯定有办法做到这一点,但我还没有设法追踪它。
xsl文件:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="kElementByType" match="*[not(self::keynode)]" use="../keynode"/>
<xsl:param name="pSource2" select="'x2.xml'"/>
<xsl:variable name="vSource2" select="document($pSource2,/)"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="info">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="keynode">
<xsl:variable name="vCurrent" select="."/>
<xsl:call-template name="identity"/>
<xsl:for-each select="$vSource2">
<xsl:apply-templates select="key('kElementByType',$vCurrent)"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
所以,使用msxls命令:
msxsl.exe x1.xml test.xsl -o out.xml
使用以下数据给出以下结果:
file x1.xml:
<root>
<info>
<id>147</id>
</info>
<nodetype>
<keynode>annajon</keynode>
<note>
<source>source1</source>
<name>Anna Jones</name>
</note>
</nodetype>
<nodetype>
<keynode>brucejon</keynode>
<note>
<source>source1</source>
<name>Bruce Jones</name>
</note>
</nodetype>
</root>
file x2.xml:
<root>
<nodetype>
<keynode>annajon</keynode>
<note>
<source>source2</source>
<name>Anna Jones</name>
</note>
</nodetype>
<nodetype>
<keynode>iangore</keynode>
<note>
<source>source2</source>
<name>Ian Gore</name>
</note>
</nodetype>
</root>
out.xml:
<?xml version="1.0" encoding="UTF-16"?><root>
<info>
<id>147</id>
</info>
<nodetype>
<keynode>annajon</keynode><note>
<source>source2</source>
<name>Anna Jones</name>
</note>
<note>
<source>source1</source>
<name>Anna Jones</name>
</note>
</nodetype>
<nodetype>
<keynode>brucejon</keynode>
<note>
<source>source1</source>
<name>Bruce Jones</name>
</note>
</nodetype>
</root>
答案 2 :(得分:0)
一种方法是将第二个xml作为参数传递,
第二种更简单的方法是将一个根元素下的两个xmls连接到
<root>
<node>
<type>a</type>
<name>joe</name>
</node>
<node>
<type>b</type>
<name>sam</name>
</node>
<node>
<type>a</type>
<name>jill</name>
</node>
</root>
然后使用2合并它
<xsl:template match="/root">
<xsl:for-each select="node">
<xsl:variable name="type" select="type"/>
<node>
<type><xsl:value-of select="$type"/></type>
<xsl:for-each select="../node[type=$type]">
<name><xsl:value-of select"name"/></name>
</xsl:for-each>
</node>
</xsl:for-each>
</xsl:template>