Самый безопасный способ извлечь все переменные ссылки из выражения 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 -->