#xml #xslt #sorting
#xml #xslt #сортировка
Вопрос:
Вот пример xml
<Data version="2.0">
<Group>
<Item>3</Item>
<Item>1</Item>
<Item>2</Item>
</Group>
<Group>
<Item>7</Item>
<Item>5</Item>
</Group>
</Data>
И для упорядочения узлов в группе по значению элемента я попытался использовать следующий xsl:
<xsl:template match="/Data">
<xsl:apply-templates select="Group">
<xsl:sort select="Item" />
</xsl:apply-templates>
</xsl:template>
Но получить только значения, даже без сортировки:
3
1
2
7
5
Итак, вопросы: 1. почему сортировка не работает 2. Как сохранить все узлы и сохранить структуру xml?
Ответ №1:
Это то, что вы хотите:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Group">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="Item">
<xsl:sort select="text()" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Первый шаблон — это «Шаблон идентификации» (Google it), который копирует входные данные в выходные данные без изменений. Затем для узла группы мы копируем его в output ( <xsl:copy>
), копируем его атрибуты, затем копируем узлы вложенных элементов после их сортировки. Они копируются, потому что внутренняя <xsl:apply-templates select="Item">
часть в конечном итоге использует шаблон идентификации, поскольку для узлов элементов нет более специфичного шаблона.
Обратите внимание, что если Group
узлы могут содержать другие данные, кроме Item
узлов, вам нужно убедиться, что они также копируются. Приведенный выше шаблон отбросил бы их.
Ответ №2:
Ответ @Jim в основном правильный.
Однако применяется к чуть более реалистичному XML-документу, такому как этот:
<Data version="2.0">
<Group>
<Item>3</Item>
<Item>1</Item>
<Item>10</Item>
<Item>2</Item>
</Group>
<Group>
<Item>7</Item>
<Item>5</Item>
</Group>
</Data>
полученный результат явно не тот, который вы хотите (10 предшествует 2 и 3):
<?xml version="1.0" encoding="utf-8"?>
<Data version="2.0">
<Group>
<Item>1</Item>
<Item>10</Item>
<Item>2</Item>
<Item>3</Item>
</Group>
<Group>
<Item>5</Item>
<Item>7</Item>
</Group>
</Data>
Вот правильное решение (которое также немного короче):
<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:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Group">
<Group>
<xsl:apply-templates select="*">
<xsl:sort data-type="number"/>
</xsl:apply-templates>
</Group>
</xsl:template>
</xsl:stylesheet>
когда это преобразование применяется к тому же XML-документу (выше), получается требуемый правильный результат:
<Data version="2.0">
<Group>
<Item>1</Item>
<Item>2</Item>
<Item>3</Item>
<Item>10</Item>
</Group>
<Group>
<Item>5</Item>
<Item>7</Item>
</Group>
</Data>
Объяснение: Использование data-type
атрибута of <xsl:sort>
для указания того, что значение ключей сортировки должно обрабатываться как число, а не как строка (по умолчанию).