xml使用xsl合并两个文件?

发布于 2024-10-06 21:20:03 字数 737 浏览 2 评论 0原文

我需要合并两个相似的 xml 文件,但仅记录与常见标记匹配的记录,例如以下示例中的

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 中执行此操作的基础知识是什么? 非常感谢。

I need to merge two similar xml files, but only records which match on common tags, e.g.<type> in the following example:

file1.xml is

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

file2.xml is

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

so that I have an output of

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

What are the basics of doing this, in xsl?
Many thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦晓ヶ微光ヅ倾城 2024-10-13 21:20:03

此样式表:

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

This stylesheet:

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

With this input (wellformed):

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

Output:

<root>
    <node>
        <type>a</type>
        <name>jill</name>
        <name>joe</name>
    </node>
    <node>
        <type>b</type>
        <name>sam</name>
    </node>
</root>
眼泪也成诗 2024-10-13 21:20:03

我认为值得添加一些我在这样做时学到的额外信息,以防它对任何其他初学者有用。我更改了测试代码名称,以便它们不会与 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>

I thought it worth adding some extra info I've learned while doing this, in case it's of use to any other beginners. I've changed my test code names so that they aren't potentially confused with some of the terms used in the xsl. I've no idea if it's the best or most efficient way of doing things, but it works (with a few caveats!).

I wanted to keep the "info" node, and the original code lost it. Coding a separate match template keeps it in the output. Also, the way I coded it, this node is only kept if it is in the input file (x1). If it's in the (x2) file, then it doesn't get kept. This has to be with the way I've written the iterations. Ideally, I'd like to keep it from either input file, but haven't worked out how to do that yet. Also, I'd like to have the option of passing the filename x2 as a parameter, via msxsl, rather than have it hard coded. There surely must be a way of doing this, but I haven't managed to track it down yet.

xsl file:

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

So, using the msxls command:

msxsl.exe x1.xml test.xsl -o out.xml

Gives the following results with the data below:

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>
鯉魚旗 2024-10-13 21:20:03

一种方法是将第二个 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>

,然后使用 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>

One way is to pass second xml as a parameter,

Second easier way is to concatenate both xmls under the one root element to

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

and then do merge it using 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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文