Удаление узлов xml с помощью xslt

Кто-нибудь знает, как скопировать только первые n узлов в файл xml и удалить остальные с помощью xslt? Итак, скажем, я хочу скопировать только первые 10 узлов и удалить остальные узлы, принадлежащие одному и тому же родителю.


person gracec    schedule 02.12.2009    source источник
comment
Пожалуйста, покажите пример входного XML, ожидаемый результат и то, как далеко вы продвинулись самостоятельно с помощью XSLT. Подсказки: Вы можете отредактировать свой собственный вопрос. Используйте кнопку 010101, чтобы отформатировать материал как код.   -  person Tomalak    schedule 02.12.2009


Ответы (4)


Вы должны просто удалить их из своего набора результатов, как:

<!-- note you must to encode 'greater than' and 'lower than' characters -->
<xsl:for-each select="parent/nodes[position() &lt;= 10]">
    ...
</xsl:for-each>
person Rubens Farias    schedule 02.12.2009

Добавьте следующий шаблон в преобразование удостоверения:

<xsl:template match="/*/*[position() &lt; 11]"/>

Как это работает: Преобразование идентичности рекурсивно копирует любой узел, который ему соответствует, в результирующий документ. Но критерии соответствия для преобразования идентичности имеют самый низкий возможный приоритет; если узлу соответствует какой-либо шаблон с более высоким приоритетом, вместо него будет использоваться этот шаблон. (Правила приоритета неясны, но они настолько хорошо разработаны, что вам редко нужно знать о них; вообще говоря, если узел соответствует двум шаблонам, XSLT выберет шаблон, чей шаблон является более конкретным.)

В этом случае мы говорим, что если узел является дочерним элементом элемента верхнего уровня (элемент верхнего уровня — это первый элемент под корнем, или /*, и его дочерние элементы, таким образом, /*/*) и его позиция в этом списке узлов 11 или выше, ее не следует копировать.

Изменить:

Уф. Все, что написано выше, верно, кроме самого главного. То, что я написал, скопирует каждый дочерний элемент элемента верхнего уровня кроме для первых десяти.

Вот полная (и правильная) версия шаблонов, которые вам понадобятся:

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

<xsl:template match="/*/*[position() &gt; 10]"/>

Вот и все. Первый шаблон копирует все, что не соответствует второму шаблону. Второй шаблон соответствует всем элементам после первых 10 и ничего с ними не делает, поэтому они не копируются в вывод.

person Robert Rossney    schedule 03.12.2009

Извините, код не вставился должным образом ниже. Вот что должно быть:

    <xsl:template match="node()|@*" name="identity">
     <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
    </xsl:template>
    <xsl:template match="inner"/>    
    <xsl:template match="/*/*[position() &lt; 11]">
<xsl:call-template name="identity"/>  
    </xsl:template>
person lizb    schedule 04.12.2009
comment
Я отредактировал свой ответ, чтобы сделать его а) более подробным и б) правильным. - person Robert Rossney; 04.12.2009

Используйте преобразование идентичности, которое скопирует исходное дерево в выходное дерево и добавит шаблон для исключения элементов, которые вы хотите исключить. Затем, поскольку вы не хотите удалять все из них, а только те, что после первых десяти, добавьте один окончательный шаблон для специальных, которые должны быть пропущены, в зависимости от их положения:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

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

  <xsl:template match="inner"/>

  <xsl:template match="inner[position() &lt; 11]">
    <xsl:call-template name="identity"/>
  </xsl:template>

</xsl:stylesheet>

для использования с XML

<?xml version="1.0" encoding="UTF-8"?>
<outer>
  <inner foo="1"/>
  <inner foo="2"/>
  <inner foo="3"/>
  <inner foo="4"/>
  <inner foo="5"/>
  <inner foo="6"/>
  <inner foo="7"/>
  <inner foo="8"/>
  <inner foo="9"/>
  <inner foo="10"/>
  <inner foo="11"/>
  <inner foo="12"/>
  <inner foo="13"/>
  <inner foo="14"/>
</outer>
person NickFitz    schedule 02.12.2009
comment
Это преобразование испортит любой элемент-потомок, который имеет 11 или более элементов с именем inner. - person Robert Rossney; 03.12.2009