Из этого канала я хочу прочитать все item
узлы, поэтому обычно //item
XPath
должен сделать свое дело. к несчастью
это не работает в этом случае.
В XPath это означает «выбрать все элементы с локальным именем item
, которые не находятся в пространстве имен ». В RSS элементы item
должны находиться в пространстве имен. Поэтому вышеприведенное никогда не должно работать с соответствующим синтаксическим анализатором XML и механизмом XPath.
Что сбивает с толку, так это то, что в XML <item>
означает «элемент с именем item, который находится в пространстве имен default , т. Е. Любое пространство имен по умолчанию находится в области действия в этом месте документа;» тогда как в XPath «item» означает элемент в no пространстве имен. (Или, можно сказать, это означает элемент в пространстве имен по умолчанию, но если у вас нет способа сообщить XPath, что такое пространство имен по умолчанию, пространство имен по умолчанию не является пространством имен. Обычно (всегда?) В XPath 1.0 нет никакого способа объявить пространство имен по умолчанию для выражений XPath.)
Другая запутанная вещь для начинающих заключается в том, что сопоставления префиксов пространства имен в исходном XML-документе не считаются значимыми процессором XPath. Когда XML-документ анализируется, создается структура данных, которая запоминает имя и пространство имен каждого элемента (и других узлов). Используемые префиксы пространства имен , включая пустой префикс пространства имен по умолчанию, считаются простым синтаксическим удобством. Подробнее об этом ниже ...
С Нокогири я мог только нас
XPath //xmlns:item
, который работает и
возвращает все узлы из канала.
Что бы это ни было, это не XPath. Может быть, это расширение к Nokogiri (очень удобное, но его синтаксис действительно нелогичный).
Так что я думаю, что могу сформулировать свой вопрос
Как: Как я могу выбрать узел из
пространство имен по умолчанию с HtmlUnit?
Давайте сформулируем это следующим образом: Как я могу выбрать элементы элемента RSS с помощью HtmlUnit? Я формулирую это так, потому что спецификация RSS (фактически вообще любая соответствующая спецификация словаря XML) не требует , что ее элементы будут в пространстве имен по умолчанию. Это верно для образца, который вы получили, но поставщик услуг может изменить это завтра и при этом полностью соответствовать RSS. Завтра поставщик услуг может использовать префикс пространства имен «rss» для этого пространства имен; или любой другой произвольный префикс. Что RSS делает , указывает, в каком пространстве имен будут его элементы: пространство имен, URI которого http://purl.org/rss/1.0/
.
Это все равно что спрашивать: «Как мне написать функцию (в Javascript, C, Java и т. Д.), Которая может сообщить мне значение переменной a
?» Обычно функция не имеет представления, какое имя переменной использовалось для чего в вызывающей программе. Все, что он знает, это значения своих аргументов. Если вы позвоните sqrt(4)
, вы получите тот же ответ, что и с a = 4; sqrt(a)
или rumpelstiltzkin = 4; sqrt(rumpelstiltzkin)
. Ясно, что имя аргумента переменной не имеет прямого влияния на результат вызова функции. Это просто должно быть имя переменной, которая содержит правильное значение. Если компилятор жаловался на то, что вы написали b = 4; return sqrt(b)
вместо использования a
, вы бы подумали, что компилятор был чокнутым. Он не должен заботиться об именах переменных, если вы используете допустимые идентификаторы.
Точно так же при обработке RSS мы не должны заботиться о том, какой префикс пространства имен используется, если он является префиксом, определяющим правильное пространство имен. Это может быть без префикса (который определяет пространство имен по умолчанию).
В XPath 2.0 вы можете использовать подстановочные знаки для пространства имен. Это очень удобно, если вы знаете, что вам не понадобятся пространства имен для устранения неоднозначности. В этом случае вы можете выбрать //*:item
. Однако я не думаю, что HTMLUnit поддерживает XPath 2.0. Также в средах XPath 2.0, таких как XSLT 2.0, вы можете указать пространство имен по умолчанию для выражений XPath, но это не поможет вам в HTMLUnit.
Итак, у вас есть пара вариантов:
- Используйте выражение XPath, которое игнорирует пространства имен, например
//*[local-name() = 'item']
.
или
- Надежный способ: зарегистрируйте префикс пространства имен для
http://purl.org/rss/1.0/
и используйте его в своем выражении XPath: //rss:item
. Тогда возникает вопрос: как зарегистрировать префикс пространства имен в HTMLUnit и передать его процессору XPath? Я быстро просмотрел документы и не нашел возможности сделать это.
Предостережение: Я должен добавить, что вышесказанное относится к соответствующим процессорам XPath. Я понятия не имею, что процессор XPath HTMLUnit использует. Есть некоторые процессоры XPath, которые игнорируют спецификации и делают мир более запутанным для всех.
Я видел здесь , что кто-то использовал следующий синтаксис для элементов в пространстве имен по умолчанию в HTMLUnit:
//:item
Но я бы не рекомендовал этого по трем причинам:
Это недопустимый XPath, поэтому вы не можете ожидать, что он будет работать с другими программами.
Он будет работать только с RSS-лентами, в которых пространство имен RSS объявлено пространством имен по умолчанию. RSS-каналы, использующие префикс пространства имен, приведут к сбою вышеуказанного.
Это удержит вас от изучения того, как реально работают пространства имен XML, и поможет сохранить статус-кво инструментов, которые не поддерживают пространства имен должным образом.
HTMLUnit в первую очередь предназначен для HTML, поэтому понятна неполная обработка XML. Но заявление о поддержке XPath, а затем об отсутствии способа объявления префиксов пространства имен является ошибкой . HTMLUnit использует пакет XPath, который кажется частью Xalan-J. В этом пакете есть способов предоставления сопоставлений пространства имен для XPath , но я не знаю, предоставляет ли HTMLUnit эту функциональность.