Как вывести дубликаты элементов с использованием XSLT? - PullRequest
6 голосов
/ 09 мая 2011

У меня есть XML, который выглядит примерно так -

<Root>
  <Fields>
    <Field name="abc" displayName="aaa" />
    <Field name="pqr" displayName="ppp" />
    <Field name="abc" displayName="aaa" />
    <Field name="xyz" displayName="zzz" />
  </Fields>
</Root>

Я хочу, чтобы вывод содержал только те элементы, которые имеют повторяющуюся комбинацию name-displayName, если они есть -

<Root>
      <Fields>
        <Field name="abc" displayName="aaa" />
        <Field name="abc" displayName="aaa" />
      </Fields>
</Root>

Как я могу сделать это с помощью XSLT?

Ответы [ 2 ]

7 голосов
/ 09 мая 2011

Это преобразование :

<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="kFieldByName" match="Field"
  use="concat(@name, '+', @displayName)"/>

 <xsl:template match=
  "Field[generate-id()
        =
         generate-id(key('kFieldByName',
                     concat(@name, '+', @displayName)
                     )[2])
        ]
  ">
     <xsl:copy-of select=
     "key('kFieldByName',concat(@name, '+', @displayName))"/>
 </xsl:template>
</xsl:stylesheet>

при применении к предоставленному документу XML :

<Root>
    <Fields>
        <Field name="abc" displayName="aaa" />
        <Field name="pqr" displayName="ppp" />
        <Field name="abc" displayName="aaa" />
        <Field name="xyz" displayName="zzz" />
    </Fields>
</Root>

дает желаемый результат :

<Field name="abc" displayName="aaa"/>
<Field name="abc" displayName="aaa"/>

Объяснение

  1. мюнхенская группировка с использованием составного ключа (для атрибутов name и displayName).

  2. Единственный шаблон в коде соответствует любому элементу Field, который является вторым в соответствующей группе. Затем внутри тела шаблона выводится вся группа.

  3. Группировка по Мюнхену - это эффективный способ группировки в XSLT 1.0. Ключи используются для эффективности.

  4. См. Также мой ответ на этот вопрос .

II. Решение XSLT 2.0 :

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

 <xsl:template match="/">
     <xsl:for-each-group select="/*/*/Field"
          group-by="concat(@name, '+', @displayName)">
       <xsl:sequence select="current-group()[current-group()[2]]"/>
   </xsl:for-each-group>
 </xsl:template>
</xsl:stylesheet>

Когда это преобразование применяется к предоставленному XML-документу (показанному выше), снова получается требуемый, правильный результат :

<Field name="abc" displayName="aaa"/>
<Field name="abc" displayName="aaa"/>

Объяснение

  1. Использование <xsl:for-each-group>

  2. Использование функции current-group().

1 голос
/ 09 мая 2011

Чтобы найти дубликаты, вам нужно перебрать элементы Field, и для каждого из них найдите набор элементов Field во всем документе, которые имеют соответствующие значения атрибутов name и displayName.Если в наборе более одного элемента, вы добавляете этот элемент в вывод.

Вот пример шаблона, который достигает этого:

<xsl:template match="Field">
    <xsl:variable name="fieldName" select="@name" />
    <xsl:variable name="fieldDisplayName" select="@displayName" />
    <xsl:if test="count(//Field[@name=$fieldName and @displayName=$fieldDisplayName]) > 1">
        <xsl:copy-of select="."/>
    </xsl:if>
</xsl:template>

Выполнение этого шаблона (обернуто всоответствующий файл XSLT) в данных примера дает следующий вывод:

<?xml version="1.0" encoding="utf-8"?>
<Root>
  <Fields>
    <Field name="abc" displayName="aaa" />
    <Field name="abc" displayName="aaa" />
  </Fields>
</Root>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...