Вопрос по xslt-1.0, xslt, xml – Преобразовать, чтобы удалить дубликаты и скопировать остальные

3

Я хочу, чтобы выходные данные xml были сгруппированы для элемента "c" в соответствии с атрибутом "f". Вот мой входной XML и XSLT. Я хочу, чтобы группа появлялась только один раз, а остальные узлы должны быть скопированы как есть. XSLT я попробовал, копирует весь ввод XML. Поэтому, если есть два или более элементов с элементом c и одним и тем же значением атрибута для «f», необходимо получить первое вхождение этой группы на выход. Мой желаемый результат также копируется.

входной XML

<M>
   <a>
      <b>
         <c f="123">
            <d>Al</d>
            <e NO="678">
               <f>Y</f>
               <g>
                  <h>FTO</h>
               </g>
            </e>
         </c>
      </b>
   </a>
  <a>
    <b>
      <c f="123">
        <d>Al</d>
        <e NO="678">
          <f>Y</f>
          <g>
            <h>FTO</h>
          </g>
        </e>
      </c>
    </b>
  </a>
  <a>
    <b>
      <c f="567">
        <d>Al</d>
        <e NO="678">
          <f>Y</f>
          <g>
            <h>FTO</h>
          </g>
        </e>
      </c>
    </b>
  </a>
  <a>
    <b>
      <somethingelse></somethingelse>
    </b>
  </a>
</M>

хотел вывод xml

<M>
  <a>
    <b>
      <c f="123">
        <d>Al</d>
        <e NO="678">
          <f>Y</f>
          <g>
            <h>FTO</h>
          </g>
        </e>
      </c>
    </b>
  </a>
  <a>
    <b>
      <c f="567">
        <d>Al</d>
        <e NO="678">
          <f>Y</f>
          <g>
            <h>FTO</h>
          </g>
        </e>
      </c>
    </b>
  </a>
  <a>
    <b>
      <somethingelse></somethingelse>
    </b>
  </a>
</M>

xslt я пытался

<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="mykey" match="c"
   use="@f"/>

  <xsl:template match=
  "c[generate-id()
      =
       generate-id(key('mykey',@f)[1])
      ]
  ">



    <xsl:text/>
    <xsl:copy-of select="key('mykey',@f)[1]"/>
  </xsl:template>
  <xsl:template match="node()|@*">
        <xsl:copy>
          <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

Ваш Ответ

4   ответа
0

<a> элементы и проверьте, есть ли какие-либо предшествующие братья и сестры с тем жеf приписывать их<c> суб-элементы. Если есть, вы нашли дубликат данногоf значение (вхождение данногоf значение, которое не является первым вхождением этого значения), и вы можете просто переопределить шаблон идентификатора, чтобы пропустить элемент:

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

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

    <xsl:template match="/M/a[b/c/@f = preceding-sibling::a/b/c/@f]"/>

</xsl:stylesheet>

Преимущество этого решения состоит в том, что оно не требует каких-либо знаний о генерации ключа или идентификатора; это только работает с основными особенностями оси XPath. Однако это может быть немного сложнее, если сравниваемые элементы не находятся на одной и той же глубине вложения / в одной и той же относительной иерархии элементов.

П.С .: Я убрал<xsl:strip-space elements="*"/> элемент, потому что я не смог его протестировать (мой Xml-процессор утверждал, что я могу использовать его, только если пропущу читаемый поток, а не файл), но не стесняйтесь повторно вставить его, если он работает для вас.

@DevNull: вы правы; То, что я запомнил, было связано исключительно с использованием значений параметров. Я упростил код в своем ответе. Спасибо.
Не могли бы вы заменить весь этот второй шаблон на<xsl:template match="/M/a[b/c/@f = preceding-sibling::a/b/c/@f]&q,uot;/>?
@DevNull: возможно. Я думаю, что я столкнулся и прочитал кое-что о выражениях XPath в шаблонеmatch хотя атрибуты не поддерживают некоторые виды ограничений. Теперь не могу найти его, но тогда у меня болит голова: - /
0

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

Скажите, если вам нужна более конкретная информация

РЕДАКТИРОВАТЬ: В качестве альтернативы и, возможно, более простой метод (я недавно использовал NAnt, поэтому я мог бы дать вам стратегию NAnt) состоит в том, чтобы отсортировать все узлы по их значениям. Затем просто запишите переменную, которая хранит текущее значение c, и сравнивайте ее до тех пор, пока значение, на которое вы смотрите, не будет равно сохраненному значению. Затем переназначьте значение и сделайте это снова!

2

This transformation:

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

     <xsl:key name="kAByC-F" match="a" use="*/c/@f"/>

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

     <xsl:template match=
      "a[*/c
       and
         not(generate-id()
            =
             generate-id(key('kAByC-F', */c/@f)[1])
             )
        ]"/>
</xsl:stylesheet>

when applied on the provided XML document:

<M>
   <a>
      <b>
         <c f="123">
            <d>Al</d>
            <e NO="678">
               <f>Y</f>
               <g>
                  <h>FTO</h>
               </g>
            </e>
         </c>
      </b>
   </a>
  <a>
    <b>
      <c f="123">
        <d>Al</d>
        <e NO="678">
          <f>Y</f>
          <g>
            <h>FTO</h>
          </g>
        </e>
      </c>
    </b>
  </a>
  <a>
    <b>
      <c f="567">
        <d>Al</d>
        <e NO="678">
          <f>Y</f>
          <g>
            <h>FTO</h>
          </g>
        </e>
      </c>
    </b>
  </a>
  <a>
    <b>
      <somethingelse></somethingelse>
    </b>
  </a>
</M>

produces the wanted, correct result:

<M>
   <a>
      <b>
         <c f="123">
            <d>Al</d>
            <e NO="678">
               <f>Y</f>
               <g>
                  <h>FTO</h>
               </g>
            </e>
         </c>
      </b>
   </a>
   <a>
      <b>
         <c f="567">
            <d>Al</d>
            <e NO="678">
               <f>Y</f>
               <g>
                  <h>FTO</h>
               </g>
            </e>
         </c>
      </b>
   </a>
   <a>
      <b>
         <somethingelse/>
      </b>
   </a>
</M>

Explanation:

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

Отличное решение :) Suresh
@ Суреш: Добро пожаловать.
1

щихc узлы:

<xsl:template match="c[generate-id() = generate-id(key('mykey',@f)[position() &gt; 1])]" />
Хм ... мне придется подумать об этом немного больше (я все еще сомневаюсь в мюнхенской группировке, но хочу учиться). Самое смешное, что, кажется, выдает желаемый результат. Кстати: ваш (показанный) вывод пропускает часть, содержащую<somethingelse> (еще не попробовал xslt).
Только это удаляет дубликатыc элементы - однако задача состоит в том, чтобы удалить полное поддерево, коренящееся вa предок каждого дубликата. Это то, что делает решение, предоставленное в моем ответе.
Спасибо за хорошее наблюдение - исправлено.

Похожие вопросы