Можно ли параметризовать скомпилированное выражение Java XPath аля семантика стиля PreparedStatement? - PullRequest
5 голосов
/ 19 июля 2011

Возможно ли с помощью стандартного механизма выражений xpath JAX-P или другого совместимого механизма скомпилировать выражение xpath, которое позволило бы параметризоваться?

Я смотрю, есть ли API, который позволил бы разработчику устанавливать заполнители в скомпилированном xpath и заменять эти значения во время выполнения.

Любое понимание этого относительно того, возможно ли это, и если есть предостережения, подводные камни или просто совет типа «не делай этого», будет с благодарностью.

(Заметьте, я исправил "пересечение потоков" ... разговаривал с коллегой по поводу xpath и регулярных выражений ... просто случилось, что у него мысленно завязали язык ... извините за путаницу)

Ответы [ 3 ]

10 голосов
/ 19 июля 2011

Вот очень простая реализация javax.xml.xpath.XPathVariableResolver

import java.util.HashMap;
import java.util.Map;
import javax.xml.namespace.QName;
import javax.xml.xpath.XPathVariableResolver;

public class SimpleVariableResolver implements XPathVariableResolver {

    private static final Map<QName, Object> vars = 
        new HashMap<QName, Object>();

    public void addVariable(QName name, Object value) {
        vars.put(name, value);
    }

    public Object resolveVariable(QName name) {
        return vars.get(name);
    }

}

Используйте это так:

public static void main(String[] args) throws ParserConfigurationException,
        SAXException, IOException, XPathExpressionException {

    DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder = domFactory.newDocumentBuilder();
    Document doc = builder.parse("workbook.xml");

    XPath xpath = XPathFactory.newInstance().newXPath();
    SimpleVariableResolver resolver = new SimpleVariableResolver();
    resolver.addVariable(new QName(null, "id"), 2);
    xpath.setXPathVariableResolver(resolver);
    XPathExpression expr = xpath.compile("/root/element[@id=$id]");
    Object result = expr.evaluate(doc, XPathConstants.NODESET);

    NodeList nodes = (NodeList) result;
    for (int i = 0; i < nodes.getLength(); i++) {
        System.out.println(nodes.item(i).getTextContent());
    }
}

В этом документе:

<root>
    <element id="1">one</element>
    <element id="2">two</element>
    <element id="3">three</element>
</root>

Выход:

two
4 голосов
/ 19 июля 2011

Я не совсем уверен, где "регулярное выражение" вписывается в ваш вопрос.

API JAXP позволяет выражению XPath содержать переменные (например, //emp[ssn=$e]), а значения переменных получают во время выполнения посредством вызова VariableResolver, который вы предоставляете как часть API. Спецификация JAXP довольно свободна в отношении того, какие значения являются приемлемыми, и это может варьироваться от одной реализации к другой.

Saxon XPath API (s9api) делает это дальше и позволяет вам явно объявлять переменные и их типы во время компиляции выражения, а затем предоставлять значения для переменных (любого типа XPath 2.0), когда выражение является казнены.

1 голос
/ 19 июля 2011

AFAIK, нет. Я исследовал это некоторое время назад и в итоге использовал String.format().

Но, таким образом, вы не сможете скомпилировать его один раз в качестве параметризованного выражения xpath, и это то, что, я думаю, вы хотите (и то, что я тоже хотел).

...