Самый безопасный способ извлечь все переменные ссылки из выражения xpath в Java

Я использую Java и саксонский процессор.

Допустим, у меня есть выражение XPath с возможными переменными ref в нем. У меня также есть некоторые пользовательские функции xpath, которые могут быть вложены на произвольную глубину, которые могут иметь переменные ссылки в качестве параметров. Так что выражение xpath довольно сложное.

Я хотел бы извлечь префикс и локальное имя для каждой переменной ref в выражении xpath без его оценки.

Я могу извлечь его, установив некоторый пользовательский XPathVariableResolver в мой xpath и оценив его. Но это может привести к большим накладным расходам, так как я хочу, чтобы извлекались только переменные ref, а не вызывать пользовательские функции, которые могут занимать много времени.

Безопасно ли это делать, просто сопоставляя шаблон со знаком '$'? Возможно, какой-то вызов API для этого был бы великолепен. Или, если API-вызов недоступен, то каких случаев мне следует избегать со знаком '$' (возможно, он может быть расположен в виде строки, и мне нужно избегать его принятия).

2 ответа

Решение

Используйте класс XPathCompiler s9api для компиляции выражения:

XPathCompiler c = new Processor(false).newXPathCompiler();
c.setAllowUndeclaredVariables(true);
XPathExecutable exp = c.compile(xpathExpression);

Внешние переменные в выражении затем доступны путем вызова:

exp.iterateExternalVariables();

Кстати, поразительно, замечены ли здесь саксонские вопросы. Если вы хотите быть уверенным в ответе, используйте саксонский форум по адресу http://saxonica.plan.io/

Если каждая переменная объявлена ​​(что должно быть так в одном модуле таблицы стилей, вы можете просто использовать это выражение XPath 2.0:

doc(yourUri)//xsl:variable/@name/string()

где префикс пространства имен "xsl" должны быть зарегистрированы в пространстве имен "http://www.w3.org/1999/XSL/Transform",

Или из таблицы стилей XSLT:

document(yourUri)//xsl:variable/@name/string()

Вы, вероятно, хотите также получить все имена параметров:

doc(yourUri)//xsl:param/@name/string()

Или имена переменных и параметров:

doc(yourUri)//*[self::xsl:variable or self::xsl:param]/@name/string()

Теперь это не дает вам набор переменных, определенных в выражениях XPath. Для этого вам понадобится парсер XPath 2.0 (и лексер). В прошлом я разрабатывал такие (с использованием механизма синтаксического анализа FXSL), но не публиковал этот анализатор. Если вам интересно, дайте мне знать, и я отправлю вам это.

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

В качестве последнего шага вы должны будете дедуплировать полученные таким образом переменные ссылки - например, используя xsl:for-each-group


Обновление:

Вот фрагмент грамматики XPath 2.0, которую я использую:

VariableReference   : '$'     QName

QName         : QNAME2 

                  |  OR
                  |  AND
                  |  EQ
                  |  NE
                  |  LT
                  |  LE
                  |  GT
                  |  GE
                  |  IS
                  |  TO
                  |  DIV
                  |  IDIV
                  |  MOD
                  |  UNION
                  |  INTERSECT
                  |  EXCEPT
                  |  THEN
                  |  ELSE
                  |  IN
                  |  RETURN
                  |  SATISFIES

И символ терминала QNAME2 определяется в лексере следующим образом:

([\i-[:]][\c-[:]]*:)?[\i-[:]][\c-[:]]*

Конечно, еще до этого нужно быть уверенным (признать), что это не часть строкового литерала, который в моем лексере я определяю как:

     ("([^"])*")+
    |
     ('([^'])*')+

Кроме того, вы должны пропустить все, что в комментариях. У меня есть это регулярное выражение для начала комментария и конца комментария:

  (\(:)         <!-- Comment start --> 

 |
  (:\))         <!-- Comment end --> 
Другие вопросы по тегам