Удаление узлов xml с помощью xslt - PullRequest
0 голосов
/ 02 декабря 2009

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

Ответы [ 4 ]

3 голосов
/ 03 декабря 2009

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

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

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

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

Edit:

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

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

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

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

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

3 голосов
/ 02 декабря 2009

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

<!-- note you must to encode 'greater than' and 'lower than' characters -->
<xsl:for-each select="parent/nodes[position() &lt;= 10]">
    ...
</xsl:for-each>
1 голос
/ 04 декабря 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>
0 голосов
/ 02 декабря 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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...