通过Muenchian方法从多个文档中对XML元素进行排序

时间:2016-08-22 11:30:36

标签: xml sorting xslt muenchian-grouping

我有几个XML文档。这些文档中的每一个都有一些具有相同名称的元素(比方说)。

其中两个XML文档的示例是(简化):

input1.xml

<xml>
<body>
    <word>A1</word>
    <word>A2</word>
    <word>B1</word>
</body>
</xml>

input2.xml

<xml>
<body>
    <word>A2</word>
    <word>B1</word>
    <word>B2</word>
</body>
</xml>

我需要(通过XSLT 1.0)对两个文件的所有元素进行排序,避免重复。

我需要的输出文件是:

output1.xml

<xml>
<body>
    <word>A1</word>
    <word>A2</word>
    <word>B1</word>
    <word>B2</word>
</body>
</xml>

我试图将输入文件命名为XSLT文件中的参数:

<xsl:param name="doc1">input1.xml</xsl:param>
<xsl:param name="doc2">input2.xml</xsl:param>

然后我创建了一个元素:

<xsl:key name="words" match="word" use="."/>

我将一些模板应用于两个文件组合的元素,如下所示:

<xsl:apply-templates select="(document($doc1)|document($doc2))//body"/>

最后,在模板中,我使用了上面创建的密钥来应用Muenchian方法:

<xsl:template match="body">
    <xsl:for-each select="//hitza[generate-id() = generate-id(key('words',.)[1])]
        <xsl:sort select="."/>
        <xsl:value-of select="."/>
    </xsl:for-each>
</xsl>

这样我得到了一个元素列表,但首先我得到了input1.xml文件的所有元素,然后是input2.xml文件的元素:

<xml>
<body>
    <word>A1</word>
    <word>A2</word>
    <word>B1</word>
    <word>A2</word>
    <word>B1</word>
    <word>B2</word>
</body>
</xml>

我无法弄清楚如何从两个文件中获取非重复项目的列表。

2 个答案:

答案 0 :(得分:1)

如果您真的需要使用XSLT 1.0处理器,那么您可以使用

($content).Replace("(?<!`r)`n","") | Set-Content out.txt -Force

基于答案https://stackoverflow.com/a/18958901/252228

使用XSLT 3.0和Saxon 9.7(可从http://saxon.sourceforge.net/获得),您可以使用

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

    <xsl:param name="input1-uri" select="'file1.xml'"/>
    <xsl:param name="input1" select="document($input1-uri)"/>

    <xsl:param name="input2-uri" select="'file2.xml'"/>
    <xsl:param name="input2" select="document($input2-uri)"/>

    <xsl:output indent="yes"/>

    <xsl:template match="/">
        <xml>
            <body>
                <xsl:variable name="words" select="$input1//word | $input2//word"/>
                <xsl:for-each select="$words">
                    <xsl:sort select="."/>
                    <xsl:if test="generate-id() = generate-id($words[. = current()])">
                        <xsl:copy-of select="."/>
                    </xsl:if>
                </xsl:for-each>
            </body>
        </xml>
    </xsl:template>

</xsl:stylesheet>

答案 1 :(得分:0)

以下是在 XSLT 1.0

中完成此任务的方法
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:math="http://www.w3.org/2005/xpath-functions/math"
    exclude-result-prefixes="xs math"
    version="3.0">

    <xsl:param name="input1-uri" select="'input1.xml'"/>
    <xsl:param name="input1" select="document($input1-uri)"/>

    <xsl:param name="input2-uri" select="'input2.xml'"/>
    <xsl:param name="input2" select="document($input2-uri)"/>

    <xsl:output indent="yes"/>

    <xsl:template match="/" name="main">
        <xml>
            <body>
                <xsl:for-each select="sort(distinct-values($input1//word | $input2//word))">
                    <word>
                        <xsl:value-of select="."/>
                    </word>
                </xsl:for-each>
            </body>
        </xml>
    </xsl:template>

</xsl:stylesheet>

请注意,这假设您直接处理<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="http://exslt.org/common" extension-element-prefixes="exsl"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:param name="doc2">input2.xml</xsl:param> <xsl:key name="words" match="word" use="."/> <!-- identity transform --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <xsl:template match="body"> <xsl:variable name="all-words"> <xsl:copy-of select="word"/> <xsl:copy-of select="document($doc2)//body/word"/> </xsl:variable> <xsl:for-each select="exsl:node-set($all-words)/word[generate-id() = generate-id(key('words',.)[1])]"> <xsl:sort select="."/> <xsl:copy-of select="."/> </xsl:for-each> </xsl:template> </xsl:stylesheet> ,并将路径作为参数传递给input1.xml