2008-10-22 3 views
13

Я нашел this page, описывая метод Muenchian, но я думаю, что я применяю его неправильно.Как выбрать уникальные узлы

Считают, что это будет возвращать набор возрастов:

/doc/class/person/descriptive[(@name='age')]/value 

1..2..2..2..3..3..4..7

Но я хотел бы, чтобы набор узлов устанавливал только один узел для каждого возраста.

1..2..3..4..7

Каждый из них, кажется, вернуть все значения, вместо уникальных значений:

/doc/class/person/descriptive[(@name='age')][not(value=preceding-sibling::value)]/value 
/doc/class/person/descriptive[(@name='age')]/value[not(value=preceding-sibling::value)] 

Что я Я пропустил?

+0

К сожалению, это выглядит как пример, который я а затем был не * метод Муанча - вместо этого автор противопоставлял его. – pc1oad1etter 2008-10-22 22:13:37

ответ

20

Вот пример:

<root> 
    <item type='test'>A</item> 
    <item type='test'>B</item> 
    <item type='test'>C</item> 
    <item type='test'>A</item> 
    <item type='other'>A</item> 
    <item type='test'>B</item> 
    <item type='other'>D</item> 
    <item type=''>A</item> 
</root> 

И XPath:

//preceding::item/preceding::item[not(.=preceding-sibling::item)]/text() 

Результаты: ABCD

EDIT: Как заметил мусио, это не захватывает последний элемент в списке, если это единственный раз, когда он появляется. Исходя из этого и комментариев Феаноры в расчет, вот лучшее решение:

/root/item[not(.=preceding-sibling::item)] 
+0

Очевидно, что вы можете использовать дополнительный XPath для ограничения на основе атрибута типа или других данных в вашем фактическом файле. У меня просто было это во время моего быстрого теста. – 2008-10-22 22:47:30

+0

Также обратите внимание, что «элемент» в XPath не является ключевым словом, это имя элемента в документе XML, над которым работают предыдущие :: и предыдущие-sibling :: axes. – 2008-10-22 22:50:55

1

Вам не хватает ссылки на «описательный» сразу после предыдущего значения? Некоторые вещи, как следующее:

/doc/class/person/descriptive[(@name='age')][not(value=preceding-sibling::descriptive[@name='age']/value)]/value 

(не проверял)

14

Вот Muenchian версия ответа Ок, используя свои данные:

<?xml version="1.0"?> 
<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:output indent="yes" method="text"/> 
    <xsl:key name="item-by-value" match="item" use="."/> 

    <xsl:template match="/"> 
    <xsl:apply-templates select="/root/item"/> 
    </xsl:template> 

    <xsl:template match="item"> 
    <xsl:if test="generate-id() = generate-id(key('item-by-value', normalize-space(.)))"> 
     <xsl:value-of select="."/> 
     <xsl:text> 
</xsl:text> 
    </xsl:if> 
    </xsl:template> 

    <xsl:template match="text()"> 
    <xsl:apply-templates/> 
    </xsl:template> 
</xsl:stylesheet> 

Это преобразование дает


B
C
D

  1. key() поиск в шаблоне для item возвращает набор узлов, содержащий все элементы item с тем же строковым значением, что и контекстный узел.
  2. Если вы применяете функцию, которая ожидает один узел к узлу, он будет работать с первым узлом в этом узле.
  3. Все вызовы generate-id() гарантируют получение одинакового идентификатора для данного узла за один проход через документ.
  4. Следовательно, тест будет истинным, если контекстный узел является тем же самым узлом, что и первый, возвращенный вызовом key().
2

Метод Muenchian использует ключи для создания уникального списка элементов из набора узлов. Для данных, ключ будет выглядеть следующим образом:

<!-- Set the name to whatever you want --> 
<xsl:key name="PeopleAges" match="/doc/class/person/descriptive[@name = 'age']/value" use="." /> 

Оттуда, я бы лично использовать xsl:apply-templates, но вы можете использовать следующий select атрибут в других местах:

<!-- you can change `apply-templates` to: `copy-of` or `for-each`. --> 
<xsl:apply-templates select="/doc/class/person/descriptive[@name = 'age']/value[count(. | key('PeopleAges', .)[1]) = 1]" /> 

Сопроводительный матч за выше намного проще:

<xsl:template match="person/descriptive[@name = 'age']/value"> 
    <strong>Age: </strong><xsl:value-of select="." /> 
</xsl:template> 
3

для тех, кто все еще ищет отборное различны в XSLT:

С XSLT 2.0 вы можете использовать "отчетливого-значение (/ документ/класс/человек/описательный [(@ имя = 'возраст')]/значение)"

Смежные вопросы