Я несколько дней борюсь с довольно сложным xpath и не могу его сформулировать.
У меня есть синтаксическое дерево из синтаксического анализатора языка, подобного c ++, и я хотел бы иметь запрос xpath, который выбирает все имена, которые не входят в имя функции.
Если быть точным, у меня есть XML-документ, подобный этому
(Весь XML-документ находится в конце вопроса, он довольно большой, я вставляю здесь простой обзор структуры документа)
Есть четыре типа узлов
a - этот элемент содержит один узел
b - содержит информацию об узле (например, "CALL_EXPRESSION")
c - содержит фактический текст (например, "printf", имена переменных ...)
d - содержит потомков текущего узла (элементы)
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 вот так
// а [Ь = "CALL_EXPRESSION"] / д / а [1]
здесь нет проблем. Теперь, если я хотел бы выбрать все узлы, которые не являются потомками этих узлов. Я бы не использовал (ancestor :: X).
Но тут возникает проблема, если я сформулирую выражение Xpath следующим образом:
* +1025 * // * [Ь = "NAME"] [нет (предка :: A [B = "CALL_EXPRESSION"] / д / а [1])]
он выбирает только те узлы, у которых нет a, у которого вообще есть дочерний элемент b = "CALL_EXPRESSION". В нашем примере он выбирает только NAME из поддерева ASSIGNMENT_EXPRESSION.
Я подозревал, что проблема в том, что ancestor :: принимает только первый элемент (в нашем случае a [b = "CALL_EXPRESSION"]) и ограничивает в соответствии с его предикатом и далее / отбрасывается. Поэтому я изменил запрос xpath так:
// * [б = "NAME"] [нет (предок :: а [../../ б = "CALL_EXPRESSION"
и позиция () = 1])]
Кажется, это работает только на более простом CALL_EXPRESSION (без DOT_EXPRESSION). Я подозревал, что путь в [] может относиться только к текущему узлу, а не к потенциальным предкам.
Но когда я использовал запрос
// * [б = "NAME"] [нет (предок :: а [Ь = "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>