Почему это недопустимое выражение запроса XPath с Xmllint, но допустимое с Saxon?

Я пытаюсь изучить запрос XPath с помощью инструментов командной строки в Linux (я прохожу курс Stanford Class2Go Introduction to Databases). Имея файл XML с именем BookstoreQ.xml книжного магазина, который содержит как книги, так и журналы, я могу выполнить следующий запрос в командная строка:

$ java -cp Saxon-HE-9.4.0.6.jar net.sf.saxon.Query -s:"BookstoreQ.xml" \
       -qs:'<results>{/Bookstore/(Book|Magazine)/Title}</results>'

и он вернет следующий результат:

<?xml version="1.0" encoding="UTF-8"?>
<results>
  <Title>A First Course in Database Systems</Title>
  <Title>Database Systems: The Complete Book</Title>
  <Title>Hector and Jeff's Database Hints</Title>
  <Title>Jennifer's Economical Database Hints</Title>
  <Title>National Geographic</Title>
  <Title>National Geographic</Title>
  <Title>Newsweek</Title>
  <Title>Hector and Jeff's Database Hints</Title>
</results>

Я получаю те же результаты, если использую xmllint в командной строке следующим образом:

$ xmllint --xpath '/Bookstore/Book/Title | /Bookstore/Magazine/Title'

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

$ xmllint --xpath '/Bookstore/(Book|Magazine)/Title' BookstoreQ.xml
XPath error: Invalid Expression
/Bookstore/(Book|Magazine)/Title
           ^
xmlXPathEval: evaluation failed
XPath evaluation failure

Зачем?

ОБНОВИТЬ:

Спасибо Фрэнсису и Майклу за помощь в понимании проблемы. Обходной путь для игры с XPath в командной строке в Linux — использовать что-то похожее на сценарий ниже.

#!/bin/bash
# This script to run xpath queries
java -cp Saxon-HE-9.4.0.6.jar net.sf.saxon.Query -qs:"<results>{$1}</results>" \ 
\!indent=yes
echo

Предполагается, что вы разместили saxon где-то в своем Путь к классам Java. Таким образом, следующий запрос ниже выведет приведенные выше результаты (с правильным отступом):

$ xpath.sh "doc('BookstoreQ.xml')/Bookstore/(Book|Magazine)/Title"

person Alex    schedule 21.02.2013    source источник


Ответы (1)


xmllib2 (используемый xmllint) знает только XPath 1.0, который не может использовать оператор объединения в шаге пути (часть (Book|Magazine)).

В XPath 1.0 вы должны написать (/Bookstore/Book/Title | /Bookstore/Magazine/Title) или /Bookstore/*[name()='Book' or name()='Magazine']/Title

Фундаментальная причина этого ограничения заключается в том, что XPath 1.0 не имеет представления о последовательностях, а только о наборах узлов. Тип данных sequence был создан для XPath 2 и XQuery. /Bookstore/(Book|Magazine)/Title передает последовательность на каждом шаге пути: последовательность с узлом документа, затем дочерний элемент Bookstore, затем объединение последовательностей дочерних элементов Book и Magazine, отсортированных в порядке документов, затем дочерние элементы Title. Оператор объединения XPath 1.0 может объединять только два набора узлов в другой набор узлов, поэтому он должен находиться в «самом внешнем» контексте выражения, а не перед или после разделителя пути.

person Francis Avila    schedule 21.02.2013
comment
Первая часть верна: эта конструкция требует XPath 2.0. Объяснение того, почему ограничение существует в XPath 1.0, неубедительно; XPath 1.0 мог бы легко разрешить выражения объединения справа от /, если бы он решил это сделать. - person Michael Kay; 21.02.2013