xml使用xsl合并两个文件?

时间:2010-12-09 19:12:15

标签: xml xslt msxsl

我需要合并两个相似的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中执行此操作的基础是什么? 非常感谢。

3 个答案:

答案 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>