Удаление последовательных дубликатов с помощью XSLT - PullRequest
2 голосов
/ 11 ноября 2011

У меня есть некоторый XML, в котором я хотел бы удалить идентичные последовательные дочерние узлы, которые принадлежат разным родителям.То есть, если дочерний (у разных родителей) узел, мое дерево XML появляется два или более раз подряд, я хочу удалить все дубликаты.

Дублирующиеся узлы, о которых я думаю, это <child>a</child> в первых двух <parent> узлах.

Пример:

Вот исходный XML:

<root>
   <parent>
      <child>a</child>
      <child>b</child>
      <child>c</child>
   </parent>

   <parent>
      <child>a</child>
      <child>bb</child>
      <child>cc</child>
   </parent>

   <parent>
      <child>aaa</child>
      <child>bbb</child>
      <child>ccc</child>
   </parent>

   <parent>
      <child>a</child>
      <child>bbbb</child>
      <child>cccc</child>
   </parent>

</root>

Вот нужный XML:

<root>
   <parent>
      <child>a</child>
      <child>b</child>
      <child>c</child>
   </parent>

   <parent>
      <child>bb</child>
      <child>cc</child>
   </parent>

   <parent>
      <child>aaa</child>
      <child>bbb</child>
      <child>ccc</child>
   </parent>

   <parent>
      <child>a</child>
      <child>bbbb</child>
      <child>cccc</child>
   </parent>

</root>

Удален только один элементно если бы в начале было, например, 5 последовательных <child>a</child> узлов (вместо 2), четыре из них были бы удалены.Я использую XSLT 2.0.

Я ценю любую помощь.

Продолжение:

Благодаря Кириллу я получаю нужные документы, однако это породило новую проблему, которую я не ожидал, если у меня естьXML-документ выглядит так:

<root>
   <parent>
      <child>a</child>
      <child>b</child>
      <child>c</child>
   </parent>

   <parent>
      <child>a</child>
      <child>b</child>
      <child>c</child>
   </parent>

   <parent>
      <child>aaa</child>
      <child>bbb</child>
      <child>ccc</child>
   </parent>

</root>

И я применяю XSLT Кирилла, я получаю это:

<root>
   <parent>
      <child>a</child>
      <child>b</child>
      <child>c</child>
   </parent>

   <parent>
   </parent>

   <parent>
      <child>aaa</child>
      <child>bbb</child>
      <child>ccc</child>
   </parent>

</root>

Как я могу также удалить <parent> </parent>?Для моего приложения могут быть другие подэлементы <parent>, которые можно удалить, если в элементе <parent> нет элемента <child>.

У меня есть решение, которое мне не нравится, - применить другое преобразование после первого.Это работает только при применении по порядку, хотя мне нужен отдельный файл XSLT и мне нужно запустить две команды вместо одной.

Вот оно:

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

 <xsl:template match="parent[not(child)]"/>

Ответы [ 3 ]

3 голосов
/ 11 ноября 2011

Использование:

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

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

  <xsl:template match="child[../preceding-sibling::parent[1]/child = .]"/>

</xsl:stylesheet>
2 голосов
/ 11 ноября 2011

Если вы можете использовать XSLT 2.0, проблема решается следующим образом:

<xsl:for-each-group select="parent" group-adjacent="child[1]">
  <xsl:for-each select="current-group()">
    <parent>
      <xsl:if test="position()=1">
        <xsl:copy-of select="current-group()[1]/child[1]"/>
      </xsl:if>
      <xsl:copy-of select="current-group()/child[position() gt 1]"/>
    </parent>
  </xsl:for-each>
</xsl:for-each-group>
0 голосов
/ 16 ноября 2011

Это ответ на недавно добавленный дополнительный вопрос :

Как мне также удалить <parent> </parent>? Для моего приложения там могут быть другие подэлементы <parent>, которые можно удалить, если в элементе нет элемента <child>.

Это преобразование является дополнением к Кириллу и выполняет желаемую очистку от получающегося в результате пустого parent элемента без необходимости второго прохода :

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

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

  <xsl:template match="child[../preceding-sibling::parent[1]/child = .]"/>

  <xsl:template match=
  "parent
     [not(child
          [not(. = ../preceding-sibling::parent[1]
                                              /child
               )
           ]
          )
     ]"/>
</xsl:stylesheet>

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

<root>
   <parent>
      <child>a</child>
      <child>b</child>
      <child>c</child>
   </parent>

   <parent>
      <child>a</child>
      <child>b</child>
      <child>c</child>
   </parent>

   <parent>
      <child>aaa</child>
      <child>bbb</child>
      <child>ccc</child>
   </parent>

</root>

желаемый, правильный результат выдается :

<root>
  <parent>
    <child>a</child>
    <child>b</child>
    <child>c</child>
  </parent>
  <parent>
    <child>aaa</child>
    <child>bbb</child>
    <child>ccc</child>
  </parent>
</root>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...