XSLT подсчитывает элементы с заданным значением - PullRequest
18 голосов
/ 06 апреля 2009

Мне нужно подсчитать количество элементов в файле XML, которые имеют определенное значение (для проверки уникальности). Файл XML выглядит так:

РЕДАКТИРОВАТЬ: Я обновил исходный "упрощенный" XML с фактическим волосатым беспорядком, который кто-то разработал. К сожалению, это приведет к тому, что все предыдущие ответы будут действительно запутанными и неправильными, если они не будут отредактированы.

<root>
  <ac>
   <Properties>
     <Property Name="Alive">
      <Properties>
        <Property Name="ID">
         <Properties>
           <Property Name="Value">
            <long>11007</long>
           </Property>
         </Properties>
        </Property>
      </Properties>
     </Property>
     <Property Name="Dead">
      <Properties>
        <Property Name="ID">
         <Properties>
           <Property Name="Value">
            <long>11008</long>
           </Property>
         </Properties>
        </Property>
      </Properties>
     </Property>
     ...
     <Property Name="MostlyDeadAllDay">
      <Properties>
        <Property Name="ID">
         <Properties>
           <Property Name="Value">
            <long>99001</long>
           </Property>
         </Properties>
        </Property>
      </Properties>
     </Property>
   </Properties>
  </ac>
</root>

Я пытаюсь определить переменную, чтобы увидеть, сколько свойств на уровне Alive / Dead имеют длинное значение (ID), как определено в параметре шаблона. Что-то в этом роде (хотя я подозреваю, что это неправильно) ...

<xsl:param name="parPropId"/>
<xsl:variable name="countProperties">
   <xsl:value-of select="count(/root/ac/
      Properties/Property/
      Properties/Property[@Name = 'ID']/
      Properites/Property[@Name = 'Value']/long = $parPropId)"/>
</xsl:variable>

Может быть несколько элементов Property, определенных на уровне «ID». Но я вполне уверен, что могу рассчитывать только на один элемент Property («Значение») под «ID» и только на один «длинный» элемент под «Value».

[Disclaimer] Кто бы ни проектировал общий XML-файл, с которым я застрял, работая с ДЕЙСТВИТЕЛЬНО, он не знал, как структурировать XML (например, обратное использование атрибутов и элементов). Я боюсь, что мое мышление XSLT было временно искажено :) в результате. [/ Отказ от ответственности]

Ответы [ 3 ]

39 голосов
/ 06 апреля 2009

Этот XPath:

count(//Property[long = '11007'])

возвращает то же значение, что и:

count(//Property/long[text() = '11007'])

... за исключением того, что первый насчитывает Property узлов, которые соответствуют критерию, а второй - long дочерних узлов, которые соответствуют критерию.

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

count(//Property[@Name = 'Alive'][long = '11007'])

потому что это означает то же самое, что и:

count(//Property[@Name = 'Alive' and long = '11007'])

Конечно, вы должны подставить значения параметров в ваш шаблон. Приведенный выше код только иллюстрирует точку.

РЕДАКТИРОВАТЬ (после редактирования вопроса)


Вы были совершенно правы в том, что XML ужасен. На самом деле, это прямой CodingHorror кандидат! Мне пришлось продолжать пересчет, чтобы отслеживать узел «Свойство», на котором я был в настоящее время. Я чувствую твою боль!

Вот, пожалуйста:

count(/root/ac/Properties/Property[Properties/Property/Properties/Property/long = $parPropId])

Обратите внимание, что я удалил все другие проверки (для идентификатора и значения). Похоже, они не обязательны, поскольку вы можете добраться до соответствующего узла, используя иерархию в XML. Кроме того, вы уже упоминали, что проверка уникальности основана только на содержимом элемента long.

2 голосов
/ 06 апреля 2009

Ваш xpath совсем немного:

count(//Property/long[text()=$parPropId])

Edit: Cerebrus совершенно справедливо указывает, что код в вашем OP (с использованием неявного значения узла) абсолютно подходит для ваших целей. На самом деле, поскольку вполне вероятно, что вы хотите работать с узлом «Свойство», а не с «длинным» узлом, вероятно, лучше запросить //Property[long=$parPropId], чем text () xpath, хотя вы могли бы обосновать последнее на основании читабельности.

Что я могу сказать, я немного устал сегодня:)

0 голосов
/ 06 апреля 2009
<xsl:variable name="count" select="count(/Property/long = $parPropId)"/>

Не проверено, но я думаю, что это должно работать. Я предполагаю, что узлы Property являются прямыми потомками корневого узла, и поэтому вынимаем ваш потомок-селектор для peformance

...