Кто-нибудь знает, как скопировать только первые n узлов в файл xml и удалить остальные с помощью xslt? Итак, скажем, я хочу скопировать только первые 10 узлов и удалить остальные узлы, принадлежащие одному и тому же родителю.
Удаление узлов xml с помощью xslt
Ответы (4)
Вы должны просто удалить их из своего набора результатов, как:
<!-- note you must to encode 'greater than' and 'lower than' characters -->
<xsl:for-each select="parent/nodes[position() <= 10]">
...
</xsl:for-each>
Добавьте следующий шаблон в преобразование удостоверения:
<xsl:template match="/*/*[position() < 11]"/>
Как это работает: Преобразование идентичности рекурсивно копирует любой узел, который ему соответствует, в результирующий документ. Но критерии соответствия для преобразования идентичности имеют самый низкий возможный приоритет; если узлу соответствует какой-либо шаблон с более высоким приоритетом, вместо него будет использоваться этот шаблон. (Правила приоритета неясны, но они настолько хорошо разработаны, что вам редко нужно знать о них; вообще говоря, если узел соответствует двум шаблонам, XSLT выберет шаблон, чей шаблон является более конкретным.)
В этом случае мы говорим, что если узел является дочерним элементом элемента верхнего уровня (элемент верхнего уровня — это первый элемент под корнем, или /*
, и его дочерние элементы, таким образом, /*/*
) и его позиция в этом списке узлов 11 или выше, ее не следует копировать.
Изменить:
Уф. Все, что написано выше, верно, кроме самого главного. То, что я написал, скопирует каждый дочерний элемент элемента верхнего уровня кроме для первых десяти.
Вот полная (и правильная) версия шаблонов, которые вам понадобятся:
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*/*[position() > 10]"/>
Вот и все. Первый шаблон копирует все, что не соответствует второму шаблону. Второй шаблон соответствует всем элементам после первых 10 и ничего с ними не делает, поэтому они не копируются в вывод.
Извините, код не вставился должным образом ниже. Вот что должно быть:
<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() < 11]">
<xsl:call-template name="identity"/>
</xsl:template>
Используйте преобразование идентичности, которое скопирует исходное дерево в выходное дерево и добавит шаблон для исключения элементов, которые вы хотите исключить. Затем, поскольку вы не хотите удалять все из них, а только те, что после первых десяти, добавьте один окончательный шаблон для специальных, которые должны быть пропущены, в зависимости от их положения:
<?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() < 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>
inner
.
- person Robert Rossney; 03.12.2009