2016-08-22 2 views
0

У меня есть несколько документов XML. Каждый из этих документов имеет некоторые элементы с тем же именем (скажем).Сортировка элементов XML из нескольких документов с помощью подхода Muenchian

Пример двух из этих 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> 

I не может понять, как получить список не повторяющихся элементов из этих двух файлов.

+0

Muenchian grouping основано на ключах, и клавиши работают над документом, а не с коллекцией документов. Не можете ли вы использовать XSLT 2.0 с Saxon или XmlPrime или Altova, чтобы использовать 'xsl: for-each-group' или' distinct-values'? –

+0

Благодарим вас за быстрый ответ. Я не знаком с xslt 2.0, поэтому я не уверен, сколько будет работы с моим кодом от 1.0 до 2.0, но я дам ему попробовать, зная, что подход Muenchian здесь не будет работать. Спасибо! –

ответ

1

Если вам действительно нужно к нему с процессором XSLT 1.0, то вы можете использовать

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

на основе ответа 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" 
    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> 
+0

спасибо! Я постараюсь сделать это как можно быстрее. –

0

Вот как вы можете выполнить эту задачу в XSLT 1.0:

<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 и передают путь к input2.xml в качестве параметра.

+0

спасибо! Я попробую это решение как можно скорее. –

+0

@JosuGomez Если на ваш вопрос ответили, пожалуйста, закройте его, приняв ответ. –

Смежные вопросы