XPATH-запрос для поиска атрибутов, содержащих ключевое слово - PullRequest
3 голосов
/ 21 мая 2011

Я пытаюсь найти что-то в нескольких атрибутах в нескольких разных узлах

Вот как я нахожу это в одном атрибуте

//*[contains(@name,'KEYA')]

Пример XML:

<cars>

<car model="2000" name="Awesome KEYA Car" name2="somethine else">Brand1</car>
<car model="2005" name="Awesome Car" name2="KEYA something else">Brand 2</car>
<car name="Awesome Car" name2="somethine else">Brand1</car>
<car dontmatch="KEYA" name2="somethine else">Brand3333</car>

</cars>

Что мне действительно нужно, так это более 10 атрибутов (они должны соответствовать только атрибутам из белого списка),

//*[contains((@name or @name2 or @name3),'KEYA')]

Использование XPATH 1.0.Есть идеи о том, как это сделать?Пробовал несколько способов, кроме повторения содержимого, но не сработало.

Ответы [ 3 ]

5 голосов
/ 21 мая 2011

Это сработало для меня

/cars/car/@*[contains(.,'KEYA')]/parent::*

enter image description here

хорошо, после редактирования, тогда я предлагаю

/cars/car/@*[name()!='dontmatch'][contains(.,'KEYA')]/parent::*

enter image description here

Если вы хотите исключить более одного атрибута, вам нужно указать дополнительные предикаты (вещи в квадратных скобках).Xpath не предоставляет способ исключить наборы имен attr, если вы не можете ограничить набор с помощью startswith() или contains() или чего-то подобного.

Существуют удобные способы запрашивать XML в других библиотеках, например, LINQ-to-XML, если вы используете .NET.Это позволит вам более точно указывать такие запросы.Но это совсем другой API.

3 голосов
/ 22 мая 2011
* +1000 * Используйте
/*/*[@*
        [contains('|name|name1|name2|name3|name4|',
                  concat('|',name(),'|')
                  )
       and
         contains(., 'KEYA')
        ]
       ]

Вот выборка, созданная Визуализатором XPath :

enter image description here

Объяснение

Вы можете указать в строке имена всех атрибутов, которые вы хотите найти . Используемый разделитель каналов (|) гарантирует, что даже если имя является началом другого, оно будет включено в поиск только при наличии отдельной подстроки с разделителями канала для этого имени.

1 голос
/ 21 мая 2011

Как насчет:

//*[contains(@name,'KEYA') or contains(@name2,'KEYA')]

Вы можете взять ответ Cheeso и сделать что-то вроде этого:

/cars/car/@*[contains(.,'KEYA') and local-name() != 'dontmatch']/parent::*

Так или иначе, вам придется построить оператор XPathлибо выбрать из белого списка атрибутов (мой пример), либо исключить атрибуты в черном списке (модифицированный пример Cheeso).

Повторное построение на основе работы Cheeso, это может упростить создание черного списка:

//@*[contains(.,'KEYA') and not(contains('dontmatch,dontmatch2', local-name()))]/parent::*

или в качестве белого списка:

//@*[contains(.,'KEYA') and contains('name,name2', local-name())]/parent::**
...