Получите различные значения в определенных атрибутах

У меня есть следующий XML-код:

<!-- language: xml -->
<Stats>
  <Stat>
    <Data Name="Value">63.76</Data>
    <Data Name="Entity">first</Data>
  </Stat>
  <Stat>
    <Data Name="Value">51.23</Data>
    <Data Name="Entity">second</Data>
  </Stat>
  <Stat>
    <Data Name="Value">46.1</Data>
    <Data Name="Entity">third</Data>
  </Stat>
  <Stat>
    <Data Name="Value">61.21</Data>
    <Data Name="Entity">first</Data>
  </Stat>
</Stats>

Я хочу фильтровать только там, где 'Data[@Name='Entity']. Использование xpath: /Stats/Stat/Data[@Name="Entity"] возвращает: первый второй третий первый

Но я хочу, чтобы результаты были уникальными. Так что я получаю только: первый второй третий

РЕДАКТИРОВАТЬ: мне нужно, чтобы это работало для xpath версии 1.0.


person Bouke Groenescheij    schedule 10.05.2012    source источник
comment
дубликат-›stackoverflow.com/questions/3016929 /   -  person rt2800    schedule 10.05.2012
comment
Однако я видел этот пост - я не думаю, что он дублируется. XML-код: ‹Статистика› ‹Статистика› ‹Значение›63,76‹/Свойство› ‹Сущность›первый‹/Свойство› ‹/Статистика› ‹/Статистика› Мой XML-код: ‹Статистика› ‹Статистика› ‹Имя данных=Значение› 63.76‹/Свойство› ‹Имя данных=Объект›первый‹/Свойство› ‹/Статистика› ‹/Статистика›   -  person Bouke Groenescheij    schedule 10.05.2012
comment
Bouke Groenescheij: Был ли мой ответ полезен или у вас остались какие-то проблемы?   -  person Dimitre Novatchev    schedule 10.05.2012


Ответы (2)


Используйте это выражение XPath 1.0:

/Stats/Stat
   [Data/@Name='Entity'
  and
   not(Data[@Name='Entity']  = following-sibling::Stat/Data[@Name = 'Entity'])
   ]
    /Data[@Name='Entity']

Проверка на основе XSLT:

<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="/">
     <xsl:copy-of select=
      "/Stats/Stat
           [Data/@Name='Entity'
          and
           not(Data[@Name='Entity']  = following-sibling::Stat/Data[@Name = 'Entity'])
           ]
            /Data[@Name='Entity']
      "/>
 </xsl:template>
</xsl:stylesheet>

когда это преобразование применяется к следующему XML-документу (созданный путем исправления неверно сформированного предоставленного текста):

<Stats>
  <Stat>
    <Data Name="Value">63.76</Data>
    <Data Name="Entity">first</Data>
  </Stat>
  <Stat>
    <Data Name="Value">51.23</Data>
    <Data Name="Entity">second</Data>
  </Stat>
  <Stat>
    <Data Name="Value">46.1</Data>
    <Data Name="Entity">third</Data>
  </Stat>
  <Stat>
    <Data Name="Value">61.21</Data>
    <Data Name="Entity">first</Data>
  </Stat>
</Stats>

приведенное выше выражение XPath оценивается, и выбранные узлы копируются в выходные данные:

<Data Name="Entity">second</Data>
<Data Name="Entity">third</Data>
<Data Name="Entity">first</Data>

Примечание. Если вам нужны только текстовые узлы ("первый", "второй" и "третий"), просто используйте одно выражение XPath:

/Stats/Stat
   [Data/@Name='Entity'
  and
   not(Data[@Name='Entity']  = following-sibling::Stat/Data[@Name = 'Entity'])
   ]
    /Data[@Name='Entity']
      /text()
person Dimitre Novatchev    schedule 10.05.2012
comment
Просто круто! Большое спасибо за быстрый и точный ответ. Я долго искал это. Особенно последний Note сделал это — и XSLT — отличный бонус! - person Bouke Groenescheij; 10.05.2012
comment
@BoukeGroenescheij: Добро пожаловать. Да, и XPath, и XSLT — увлекательные, мощные и элегантные языки. - person Dimitre Novatchev; 10.05.2012

Вам нужно сказать, какая версия XPath. В XPath 2.0 это тривиально:

distinct-values(/Stats/Stat/Data/@Name)
person Michael Kay    schedule 10.05.2012
comment
Спасибо. Вы правы - извините, мне это нужно для XPath 1.0. - person Bouke Groenescheij; 10.05.2012
comment
Кстати, приведенный выше код не дает желаемых результатов, так как возвращает Value и Entity. После изменения его на: Different-values(/Stats/Stat/Data[@Name='Entity]) он работает - теперь мне нужно преобразовать его в XPath версии 1.0... - person Bouke Groenescheij; 10.05.2012