XPath выбирает несколько элементов с предикатами

У меня есть запрос XPath, который делает то, что я хочу, а именно выбор объединения "фамилия" и "заданные имена" с заданными предикатами (это фактически либо/или что мне нужно, но соединение работает отлично):

/header/authors/surname[./text() and @id='1']
|
/header/authors/given-names[./text() and @id='1']

Однако это кажется слишком длинным для меня, и я чувствую, что должно быть возможно сделать что-то более сжатое, например:

/header/authors/(surname|given-names)[./text() and @id='1']

... но эта версия недействительна XPath.

Может ли кто-нибудь рассказать мне о более аккуратном способе написания исходного выражения XPath, который не требует, чтобы полный путь был написан дважды?

Спасибо

Ричард

Ответ 1

Во-первых, это действительный XPath 2.0:

/header/authors/(surname|given-names)[./text() and @id='1'] 

Во-вторых, этот XPath 1.0:

/header/authors/*[self::surname|self::given-names][text()][@id='1'] 

Ответ 2

Как насчет

/header/authors/*[(name() = "surname" or name()="given-names") and ./text() and @id='1'] 

Ответ 3

В дополнение к Алехандро и Севе хорошие ответы, другая альтернатива

(/header/authors/surname | /header/authors/given-names)[text() and @id='1']

Это справедливо в XPath 1.0. Он по-прежнему немного избыточен, но более краткий, чем длинный вариант в вашем вопросе.

Еще одна альтернатива - объявить переменную для элементов фамилии и переменную для элементов с заданным именем, а затем

($surnames | $given-names)[text() and @id='1']

Это, вероятно, будет больше в общем, но легче читать, чем указано выше.