xml使用xsl合并两个文件?

xml使用xsl合并两个文件?,xml,xslt,msxsl,Xml,Xslt,Msxsl,我需要合并两个类似的xml文件,但只合并与公共标记匹配的记录,例如下面示例中的: file1.xml是 <node> <type>a</type> <name>joe</name> </node> <node> <type>b</type> <name>sam</name> </node> A. 乔 B 山姆 fil

我需要合并两个类似的xml文件,但只合并与公共标记匹配的记录,例如下面示例中的

file1.xml是

<node>
    <type>a</type>
    <name>joe</name>
</node>
<node>
    <type>b</type>
    <name>sam</name>
</node>

A.
乔
B
山姆
file2.xml是

<node>
    <type>a</type>
    <name>jill</name>
</node>

A.
吉尔
所以我有一个

<node>
    <type>a</type>
    <name>jill</name>
    <name>joe</name>
</node>
<node>
    <type>b</type>
    <name>sam</name>
</node>

A.
吉尔
乔
B
山姆
在xsl中,这样做的基础是什么? 非常感谢。

此样式表:

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

使用此输入(格式正确):


A.
乔
B
山姆
输出:

<root>
    <node>
        <type>a</type>
        <name>jill</name>
        <name>joe</name>
    </node>
    <node>
        <type>b</type>
        <name>sam</name>
    </node>
</root>

A.
吉尔
乔
B
山姆

一种方法是将第二个xml作为参数传递

第二种更简单的方法是将一个根元素下的两个XML连接到

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

A.
乔
B
山姆
A.
吉尔
然后使用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>

我认为值得在做这件事的同时添加一些我学到的额外信息,以防对其他初学者有用。我已经更改了测试代码名,以便它们不会与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>
使用以下数据给出以下结果:

文件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>

147
安纳洪
资料来源1
安娜·琼斯
布鲁塞戎
资料来源1
布鲁斯·琼斯
文件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>

安纳洪
资料来源2
安娜·琼斯
伊恩戈尔
资料来源2
伊恩·戈尔
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>

147
安纳洪
资料来源2
安娜·琼斯
资料来源1
安娜·琼斯
布鲁塞戎
资料来源1
布鲁斯·琼斯

Chernyshow:您仍然需要迭代uniques类型。感谢Max的建议。我曾经考虑过剪切和粘贴这两个文件,然后进行排序/合并,但也无法理解:我对xsl非常陌生,但确实喜欢它!对不起,我不能发布任何一个答案,因为我没有atm机的声誉。我知道在匹配模板上同时使用name和match,但没有意识到利用这一事实的真实模式。非常感谢你的回答,非常感谢你的回答。非常感谢,这非常有效,就像在测试系统上一样。现在我需要尝试将它应用到我的实际系统中,这是一个更复杂的问题,因为我简化了它。不过,我现在有一些具体的工作要做,可以从文档中了解到功能等在做什么。有一件事我想澄清一下,因为我还没有找到它(毫无疑问,它是基本的,因为我已经看到它被大量使用!),但是“@”字符在做什么,比如“node()|@*”@debs:You's wellcome。关于你的问题:
@*
属性::*
的缩写,意思是任何属性。在对代码进行了更多的研究之后,我开始意识到我不知道[match=“node()|@*”]语句在做什么。我以为它是在测试名为“node”的节点,但怀疑它是某种保留字,好像我将实际的节点名称更改为(比如)tnode,xsl不会更改,但如果用tnode替换节点,xsl就会中断。我可以用一本基本的入门书来解释这一切,因此如果任何人有任何可以推荐的链接(或书籍),我将不胜感激。这本书非常清楚地解释了身份等的一些基本知识。对我来说:当你知道如何做时,参数传递很容易:[msxsl.exe x2.xml test.xsl-o out.xml pSource2=“x1.xml”]在xsl文件中用x1.xml替换x2.xml。如果未设置任何参数,“select”语句将设置默认值。
<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>
<?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>