Я несколько дней борюсь с довольно сложным xpath, и я не могу его сформулировать. У меня есть синтаксическое дерево из синтаксического анализатора языка C ++, и я хотел бы иметь запрос xpath, который выбирает все имена, которых нет в имени функции.
Чтобы быть конкретным, у меня есть XML-документ, подобный этому
(Весь XML-документ находится в конце вопроса, он довольно большой, я вставляю здесь простой обзор структуры документа) есть четыре типа узлов
a - этот элемент содержит один узел
b - содержит информацию о узел (например, «CALL_EXPRESSION»)
c - содержит фактический текст (например, «printf», имена переменных ...)
d - содержит порядковые номера текущего узла (элементы a)
CALL_EXPRESSION DOT_EXPRESSION NAME_EXPRESSION NAME NAME_EXPRESSION NAME PARAMS NAME_EXPRESSION NAME CALL_EXPRESSION NAME_EXPRESSION NAME PARAMS NAME_EXPRESSION NAME ASSIGNMENT_EXPRESSION NAME_EXPRESSION NAME NAME_EXPRESSION NAME
Я хотел бы сформулировать запрос Xpath, который бы выбрал все ИМЯ, которые не являются потомками CALL_EXPRESSION / * [1]. (Это означает, что я хотел бы выбрать все переменные, а не имена функций).
Чтобы выбрать все имена функций, я могу использовать Xpath следующим образом
// a [b = "CALL_EXPRESSION"] / d / a [1]
здесь нет проблем. Теперь, если я хочу выбрать все узлы, которые не являются потомками этих узлов. Я бы использовал not (ancestor :: X).
Но вот проблема, если я сформулирую выражение Xpath следующим образом:
// * [b = "ИМЯ"] [не (предок :: a [b = "CALL_EXPRESSION"] / d / a [1])]
он выбирает только узлы, у которых вообще нет a, у которого есть дочерний элемент b = "CALL_EXPRESSION". В нашем примере он выбирает только NAME из поддерева ASSIGNMENT_EXPRESSION.
Я подозревал, что проблема в том, что предок :: берет только первый элемент (в нашем случае a [b = "CALL_EXPRESSION"]) и ограничивает его в соответствии с его предикатом, а далее / отбрасываются. Итак, я изменил запрос xpath следующим образом:
//*[b="NAME" visible[not(ancestor::a[../../b="CALL_EXPRESSION "and position () = 1])]
Кажется, это работает только с более простым CALL_EXPRESSION (без DOT_EXPRESSION). Я подозревал, что путь в [] может относиться только к текущему узлу, а не к потенциальным предкам. Но когда я использовал запрос
// * [b = "ИМЯ"] [не (предок :: a [b = "CALL_EXPRESSION"])]
он работал, как можно было бы предположить (были выбраны все ИМЯ, не имеющие предка CALL_EXPRESSION).
Есть ли способ сформулировать нужный мне запрос? И почему запросы не работают?
Заранее спасибо :)
XML
<a>
<b>CALL_EXPRESSION</b>
<c>object.method(a)</c>
<d>
<a>
<b>DOT_EXPRESSION</b>
<c>object.method</c>
<d>
<a>
<b>NAME_EXPRESSION</b>
<c>object</c>
<d>
<a>
<b>NAME</b>
<c>object</c>
<d>
</d>
</a>
</d>
</a>
<a>
<b>NAME_EXPRESSION</b>
<c>method</c>
<d>
<a>
<b>NAME</b>
<c>method</c>
<d>
</d>
</a>
</d>
</a>
</d>
</a>
<a>
<b>PARAMS</b>
<c>(a)</c>
<d>
<a>
<b>NAME_EXPRESSION</b>
<c>a</c>
<d>
<a>
<b>NAME</b>
<c>a</c>
<d>
</d>
</a>
</d>
</a>
</d>
</a>
</d>
</a>
<a>
<b>CALL_EXPRESSION</b>
<c>puts(b)</c>
<d>
<a>
<b>NAME_EXPRESSION</b>
<c>puts</c>
<d>
<a>
<b>NAME</b>
<c>puts</c>
<d>
</d>
</a>
</d>
</a>
<a>
<b>PARAMS</b>
<c>(b)</c>
<d>
<a>
<b>NAME_EXPRESSION</b>
<c>b</c>
<d>
<a>
<b>NAME</b>
<c>b</c>
<d>
</d>
</a>
</d>
</a>
</d>
</a>
</d>
</a>
<a>
<b>ASSIGNMENT_EXPRESSION</b>
<c>c=d;</c>
<d>
<a>
<b>NAME_EXPRESSION</b>
<c>c</c>
<d>
<a>
<b>NAME</b>
<c>c</c>
<d>
</d>
</a>
</d>
</a>
<a>
<b>NAME_EXPRESSION</b>
<c>d</c>
<d>
<a>
<b>NAME</b>
<c>d</c>
<d>
</d>
</a>
</d>
</a>
</d>
</a>