Как посчитать разные значения в узле? - PullRequest
13 голосов
/ 30 сентября 2008

Как посчитать разные значения в узле в XSLT?

Пример: я хочу посчитать количество стран в узлах страны, в данном случае это будет 3.

<Artists_by_Countries>
    <Artist_by_Country>
        <Location_ID>62</Location_ID>
        <Artist_ID>212</Artist_ID>
        <Country>Argentina</Country>
    </Artist_by_Country>
    <Artist_by_Country>
        <Location_ID>4</Location_ID>
        <Artist_ID>108</Artist_ID>
        <Country>Australia</Country>
    </Artist_by_Country>
    <Artist_by_Country>
        <Location_ID>4</Location_ID>
        <Artist_ID>111</Artist_ID>
        <Country>Australia</Country>
    </Artist_by_Country>
    <Artist_by_Country>
        <Location_ID>12</Location_ID>
        <Artist_ID>78</Artist_ID>
        <Country>Germany</Country>
    </Artist_by_Country>
</Artists_by_Countries>

Ответы [ 4 ]

26 голосов
/ 30 сентября 2008

Если у вас большой документ, вы, вероятно, захотите использовать «метод Мюнхена», который обычно используется для группировки, чтобы идентифицировать отдельные узлы. Объявите ключ, который индексирует вещи, которые вы хотите посчитать, по значениям, которые различаются:

<xsl:key name="artists-by-country" match="Artist_by_Country" use="Country" />

Затем вы можете получить элементы <Artist_by_Country>, которые имеют разные страны, используя:

/Artists_by_Countries
  /Artist_by_Country
    [generate-id(.) =
     generate-id(key('artists-by-country', Country)[1])]

и вы можете сосчитать их, заключив это в вызов функции count().

Конечно, в XSLT 2.0 это так же просто, как

count(distinct-values(/Artists_by_Countries/Artist_by_Country/Country))
6 голосов
/ 30 сентября 2008

В XSLT 1.0 это не очевидно, но следующее должно дать вам представление о требовании:

count(//Artist_by_Country[not(Location_ID=preceding-sibling::Artist_by_Country/Location_ID)]/Location_ID)

Чем больше элементов в вашем XML, тем дольше это занимает, так как он проверяет каждый предшествующий элемент каждого отдельного элемента.

5 голосов
/ 30 сентября 2008

Попробуйте что-то вроде этого:

count(//Country[not(following::Country/text() = text())])

«Дайте мне счетчик всех узлов страны без следующей страны с соответствующим текстом»

Интересным битом этого выражения, IMO, является , следующий за осью.

Вы также можете удалить первое /text() и заменить второе на .

0 голосов
/ 30 сентября 2008

Если у вас есть контроль над генерацией xml в первый раз в стране, вы можете добавить к узлу страны атрибут, такой как Different = 'true', пометить страну как "использованную", и впоследствии не добавлять отдельный атрибут, если вы встретить эту страну снова.

Вы могли бы тогда сделать

<xsl:for-each select="Artists_by_Countries/Artist_by_Country/Country[@distinct='true']" />
...