Использование XSLT для удаления повторяющихся элементов в простом XML-файле

Я новичок в XSLT, и у меня возникла проблема с удалением дубликатов из простого XML-файла. Потратил много времени, пытаясь получить это, но это никогда не бывает правильно. Вот исходный файл:

<?xml version="1.0" encoding="UTF-16"?>
<language>
    <lang name="welcome">welcom</lang>
    <lang name="open">Open</lang>
    <lang name="close">Close</lang>
    <lang name="welcome">Welcome</lang>
    <lang name="copy">Copy</lang>
</language>

Желаемый результат таков:

<?xml version="1.0" encoding="UTF-16"?>
<language>
    <lang name="open">Open</lang>
    <lang name="close">Close</lang>
    <lang name="welcome">Welcome</lang>
    <lang name="copy">Copy</lang>
</language>

Фактические файлы намного больше, чем это, и «язык» и «имя» могут измениться позже в файле, и я хочу сохранить только последний дубликат. По сути, если тег и атрибуты дублируются, сохраните только последнюю запись. Я надеюсь, что это возможно с XSLT 1.0. Если нет, я всегда могу использовать несколько скриптов на случай, если язык изменится на что-то другое. Заранее спасибо!


person CosmicDan    schedule 23.10.2012    source источник
comment
Вы упоминаете в своем вопросе об атрибутах. Можно ли иметь несколько атрибутов для элементов lang или это всегда будет только атрибут name?   -  person Tim C    schedule 23.10.2012
comment
Атрибутов может быть больше, но мне нужно сравнить только тег и атрибут имени. Другие атрибуты, если они появятся, в любом случае будут идентичными.   -  person CosmicDan    schedule 23.10.2012


Ответы (2)


Следующий XSLT должен ответить на ваш вопрос:

    <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="lang[@name=following-sibling::lang/@name]"/>
</xsl:stylesheet>

Таким образом, вы фильтруете каждый элемент lang, у которого есть следующий родственный элемент lang с тем же значением атрибута name.

person Vincent Biragnet    schedule 23.10.2012

Более общее и гораздо более эффективное (линейное) решение, чем квадратичная временная сложность (O(N^2)) принятого в настоящее время ответа. Это особенно важно при обработке большого XML-документа, поскольку OP сказал нам, что фактические документы::

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kLangByName" match="lang" use="@name"/>

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

 <xsl:template match=
 "lang[not(generate-id()
      =
       generate-id(key('kLangByName', @name)[last()]))]"/>
</xsl:stylesheet>

Когда это преобразование применяется к предоставленному XML-документу:

<language>
    <lang name="welcome">welcom</lang>
    <lang name="open">Open</lang>
    <lang name="close">Close</lang>
    <lang name="welcome">Welcome</lang>
    <lang name="copy">Copy</lang>
</language>

получен желаемый правильный результат:

<language>
   <lang name="open">Open</lang>
   <lang name="close">Close</lang>
   <lang name="welcome">Welcome</lang>
   <lang name="copy">Copy</lang>
</language>

Пояснение:

Использование мюнхийского метода группировки.

person Dimitre Novatchev    schedule 23.10.2012
comment
Эй, спасибо за это. Да, это был большой объем данных, но небольшой, и его не нужно запускать регулярно. Но я понимаю, что вы имеете в виду, так что спасибо за совет на будущее :) - person CosmicDan; 17.04.2014