XSLT合并来自两个文档

时间:2017-02-27 14:18:41

标签: xml xslt

我有两个需要合并的XML文档。每个元素都有一个定义的ID。如果一个元素在两个文档中都是唯一的 - >将被添加到结果中,如果不是 - >属性将被合并。

main.xml中

<main>
    <el id="1" attr1="value1" />
    <el id="2" attr2="value2" default-attr="def" />
</main>

snippet.xml

<main>
    <el id="2" attr2="new value2" new-attr="some value" />
    <el id="3" attr3="value3" />
</main>

为result.xml

<main>
    <el id="1" attr1="value1" />
    <el id="2" attr2="new value2" default-attr="def" new-attr="some value" />
    <el id="3" attr3="value3" />
</main>

el [@ id = 2]中的属性被合并,并且从snippet.xml覆盖了值。

我试过这个:

merge.xlst

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <xsl:param name="snippetDoc" select="document(snippet.xml)" />

    <xsl:template match="@* | node() | comment()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node() | comment()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="el">
        <xsl:copy>
            <!-- how to distinguish between @ids of two documents? -->
            <xsl:copy-of select="$snippetDoc/main/el/[@id = @id]/@*" />
            <xsl:apply-templates select="@*" />
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

但它需要能够区分两个文档中的相同属性。更重要的是,这不会复制snippet.xml中的唯一元素。

感谢您的帮助!

1 个答案:

答案 0 :(得分:1)

你正在寻找的表达是......

 <xsl:copy-of select="$snippetDoc/main/el[@id=current()/@id]/@*" />

您还应该在<xsl:apply-templates select="@*" />之后添加它,以便您可以利用新属性覆盖任何现有属性(如果它们具有相同名称)的事实。

要在代码段中添加主文档中没有匹配元素的元素,您需要在匹配main元素的模板中执行此操作。

    <xsl:template match="main">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
            <xsl:copy-of select="$snippetDoc/main/el[not(@id=current()/el/@id)]" />
        </xsl:copy>     
    </xsl:template>

试试这个XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <xsl:param name="snippetDoc" select="document('snippet.xml')" />

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="el">
        <xsl:copy>
            <!-- how to distinguish between @ids of two documents? -->
            <xsl:apply-templates select="@*" />
            <xsl:copy-of select="$snippetDoc/main/el[@id=current()/@id]/@*" />
        </xsl:copy>
    </xsl:template>

    <xsl:template match="main">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
            <xsl:copy-of select="$snippetDoc/main/el[not(@id=current()/el/@id)]" />
        </xsl:copy>     
    </xsl:template>

</xsl:stylesheet>

请注意,node()实际上是*|text()|comment()|processing-instruction()的简称,因此实际上不需要node()|comment()