2009-12-02 3 views
0

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

+0

Просьба показать пример ввода XML, ожидаемого результата и того, как далеко вы поделились с XSLT. Советы: вы можете отредактировать свой собственный вопрос. Используйте кнопку «010101», чтобы форматировать материал как код. – Tomalak

ответ

3

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

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

+1 Действительно простой и аккуратный. Я бы сделал то же самое. –

0

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

<?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> 
+0

Это преобразование испортит любой элемент потомка, который имеет 11 или более элементов с именем 'inner'. –

3

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

<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 и ничего не делает с ними, поэтому они не копируются на вывод.

1

К сожалению, код не вставлялся правильно. Вот что это должно быть:

<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

Я отредактировал свой ответ, чтобы сделать его a) более подробным и b) не ошибаюсь. –

Смежные вопросы