XPath приводит к пустой строке

Ниже приведен мой файл XML

<xyzevent xmlns="http://www.xyz.com/common/xyzevent/v1" xmlns:xsi="http://www.w3.org2001XMLSchema-instance">
<header>
 ----
</header>
<subscription xmlns="http://www.xyz.com/common/xyzevent/source/v1">
  <sender></sender>
  <receiver>
    <clientsubscription>
        <servicemap>nanna</servicemap>
    </clientsubscription>
  </receiver>
</subscription> 
</xyzevent>

Когда я строил org.w3c.dom.Document из этого XML и применяя XPathExperssion с выражением

/xyzevent/subscription/receiver/clientsubscription/servicemap/text()

выдает пустую строку. В чем может быть проблема с выражением?

Спасибо


person Pokuri    schedule 26.08.2011    source источник


Ответы (4)


Это потому, что ваш XML-документ использует пространство имен. XPath действительно раздражает с пространствами имен. Чтобы убедиться в этом, удалите два символа xmlns=http://.../v1 из документа и запустите выражение XPath для неподдающегося проверке XML-файла без пространства имен. Это будет соответствовать.

Происходит следующее: ваше выражение XPath пытается выбрать /xyzevent, когда ваш документ содержит {http://.../v1}:xyzevent, что не одно и то же.

Существуют различные способы обойти эту проблему. Правильный способ - настроить NamespaceContext, чтобы вы могли использовать нотацию prefix:localName в своем выражении XPath и префиксы разрешались в правильный URI. Об этом есть краткое описание в документах по xerces и в некоторых других в другом месте StackOverflow. Подробное описание можно найти на ibm.com.

Ваш NamespaceContext будет содержать два (или более) сопоставления:

{
    event => http://www.xyz.com/common/xyzevent/v1
    source => http://www.xyz.com/common/xyzevent/source/v1
}

Тогда ваше выражение XPath может стать /event:xyzevent/source:subscription/source:receiver/.../text().

В качестве неприятного обходного пути вы можете переписать выражение xpath для выбора с помощью функции local-name():

/*[local-name()='xyzevent']/*[local-name()='subscription'/ ...

В этом случае выражение соответствует любому элементу с локальным именем xyzevent, независимо от URI пространства имен.

person Barend    schedule 26.08.2011
comment
После удаления xmlns=http://.../v1 из обоих мест я могу получить значение. Но не могли бы вы объяснить мне, как построить NamespaceContext, чтобы получить, когда у нас есть оба значения пространства имен в документе... - person Pokuri; 26.08.2011
comment
@Pokuri Зарегистрируйте два отдельных префикса в своем NamespaceContext, например. event и source с соответствующими URI для каждого. Ваше выражение XPath станет /event:xyzevent/source:subscription/source:receiver/... - person Barend; 26.08.2011
comment
Но NamespaceContext ожидает один namespaceURI и один или несколько префиксов. Тогда как я могу передать два NamespaceContext в XPath.setNamespaceContext(namespaceContext); метод - person Pokuri; 26.08.2011
comment
Пример на stackoverflow.com /questions/914013/ охватывает это. - person Barend; 26.08.2011
comment
действительно полезные ссылки. Большое спасибо. - person Pokuri; 26.08.2011

Ваш XML имеет пространство имен по умолчанию: xmlns="http://www.xyz.com/common/xyzevent/v1", поэтому вам необходимо определить его в вашем движке XML/XPath.

Или используйте этот XPath:

/*[local-name() = 'xyzevent']
    /*[local-name() = 'subscription']
        /*[local-name() = 'receiver']
            /*[local-name() = 'clientsubscription']
                /*[local-name() = 'servicemap']
                    /text()
person Kirill Polishchuk    schedule 26.08.2011

xyzevent — это ваш корневой элемент, поэтому вам просто нужно использовать "/subscription/receiver/clientsubscription/servicemap/text()".

person Koraktor    schedule 26.08.2011

Я оценил ваше выражение по следующей ссылке:

http://www.whitebeam.org/library/guide/TechNotes/xpathtestbed.rhtm

И кажется, он выбирает «няню».

person suat    schedule 26.08.2011