Java XPath: запросы с пространством имен по умолчанию xmlns

Я хочу выполнить запрос XPath к этому файлу (показан фрагмент):

<?xml version="1.0" encoding="UTF-8"?>
<!-- MetaDataAPI generated on: Friday, May 25, 2007 3:26:31 PM CEST -->
<ModelClass xmlns="http://xml.sap.com/2002/10/metamodel/webdynpro" xmlns:IDX="urn:sap.com:WebDynpro.ModelClass:2.0">
    <ModelClass.Parent>
        <Core.Reference package="com.test.mypackage" name="ModelName" type="Model"/>

Это фрагмент кода, который я использую:

DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document document = builder.parse(new File(testFile));
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
xpath.setNamespaceContext( new NamespaceContext() {
    public String getNamespaceURI(String prefix) {
...

String result = xpath.evaluate(xpathQueryString, document);
System.out.println(result);

Проблема, с которой я сталкиваюсь, заключается в том, что при ссылке на пространство имен по умолчанию в запросе XPath метод getNamespaceURI не вызывается для его разрешения. Этот запрос, например, ничего не извлекает:

//xmlns:ModelClass.Parent/xmlns:Core.Reference[@type=\"Model\"]/@package

Теперь я попытался «обмануть» синтаксический анализатор, заменив xmlns поддельным префиксом d, а затем соответствующим образом написав метод getNamespaceURI (чтобы вернуть http://xml.sap.com/2002/10/metamodel/webdynpro, когда встречается d). В этом случае вызывается getNamespaceURI, но результатом вычисления выражения XPath всегда является пустая строка.

Если я уберу пространства имен из файла и из выражения запроса XPath, я смогу получить нужную строку (com.test.mypackage).

Есть ли способ заставить все работать правильно с пространством имен по умолчанию?


person Pietro M.    schedule 23.05.2012    source источник


Ответы (2)


В вашем контексте Namespace привяжите префикс по вашему выбору (например, df) к URI пространства имен в документе.

xpath.setNamespaceContext( new NamespaceContext() {
    public String getNamespaceURI(String prefix) {
      switch (prefix) {
        case "df": return "http://xml.sap.com/2002/10/metamodel/webdynpro";
        ...
       }
    });

а затем используйте этот префикс в ваших выражениях пути для уточнения имен элементов, например. /df:ModelClass/df:ModelClass.Parent/df:Core.Reference[@type = 'Model']/@package.

person Martin Honnen    schedule 23.05.2012
comment
Убедитесь, что вы также создали DocumentBuilder с учетом пространства имен docs.oracle.com/javase/6/docs/api/javax/xml/parsers/ перед работой с пространствами имен. - person Martin Honnen; 23.05.2012
comment
Это помогло. Я думал, что DocumentBuilder по умолчанию знает о пространствах имен. Еще раз спасибо. - person Pietro M.; 23.05.2012

Спецификация XPath 1.0 требует, чтобы «отсутствие префикса означало отсутствие пространства имен». Так что JAXP, который был разработан для XPath 1.0, совершенно прав, чтобы не дать вам привязать «нулевой префикс» к какому-то ненулевому пространству имен.

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

person Michael Kay    schedule 23.05.2012