Python lxml - xpath не находит элементы [duplicate]

Обратите внимание, что в случае отражения вы получаете NoSuchMethodException, а с неотражающим кодом вы получаете NoSuchMethodError. Я, как правило, смотрю в самых разных местах, когда сталкиваюсь с одним против другого.

13
задан kjhughes 25 November 2016 в 02:18
поделиться

1 ответ

Определение пространств имен в XPath (рекомендуется)

У самого XPath нет способа связать префикс пространства имен с пространством имен. Такие средства предоставляются библиотекой хостинга.

Рекомендуется использовать эти средства и определять префиксы пространства имен, которые затем могут использоваться для квалифицирования XML-элементов и имен атрибутов по мере необходимости.


Вот некоторые из различных механизмов, которые хосты XPath предоставляют для указания привязок префикса пространства имен к URI пространства имен:

XSLT:

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:i="http://schema.intuit.com/finance/v3">
   ...

Perl ( LibXML ):

my $xc = XML::LibXML::XPathContext->new($doc);
$xc->registerNs('i', 'http://schema.intuit.com/finance/v3');
my @nodes = $xc->findnodes('/i:IntuitResponse/i:QueryResponse');

Python ( lxml ):

from lxml import etree
f = StringIO('<IntuitResponse>...</IntuitResponse>')
doc = etree.parse(f)
r = doc.xpath('/i:IntuitResponse/i:QueryResponse', 
              namespaces={'i':'http://schema.intuit.com/finance/v3'})

Python ( ElementTree ):

namespaces = {'i': 'http://schema.intuit.com/finance/v3'}
root.findall('/i:IntuitResponse/i:QueryResponse', namespaces)

Java (SAX):

NamespaceSupport support = new NamespaceSupport();
support.pushContext();
support.declarePrefix("i", "http://schema.intuit.com/finance/v3");

Java (XPath):

xpath.setNamespaceContext(new NamespaceContext() {
    public String getNamespaceURI(String prefix) {
      switch (prefix) {
        case "i": return "http://schema.intuit.com/finance/v3";
        // ...
       }
    });

C #:

XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("i", "http://schema.intuit.com/finance/v3");
XmlNodeList nodes = el.SelectNodes(@"/i:IntuitResponse/i:QueryResponse", nsmgr);

xmlstarlet:

-N i="http://schema.intuit.com/finance/v3"

JavaScript:

См. Реализация разрешенного пользователем пространства имен Resolver :

function nsResolver(prefix) {
  var ns = {
    'i' : 'http://schema.intuit.com/finance/v3'
  };
  return ns[prefix] || null;
}
document.evaluate( '/i:IntuitResponse/i:QueryResponse', 
                   document, nsResolver, XPathResult.ANY_TYPE, 
                   null );

PhP :

Адаптировано из @ ответа Томалака с использованием DOMDocument :

$result = new DOMDocument();
$result->loadXML($xml);

$xpath = new DOMXpath($result);
$xpath->registerNamespace("i", "http://schema.intuit.com/finance/v3");

$result = $xpath->query("/i:IntuitResponse/i:QueryResponse");

См. также @ Канонический Q / A IMSoP на PHP Пространства имен SimpleXML .

VBA:

xmlNS = "xmlns:i='http://schema.intuit.com/finance/v3'"
doc.setProperty "SelectionNamespaces", xmlNS  
Set queryResponseElement =doc.SelectSingleNode("/i:IntuitResponse/i:QueryResponse")

Как только вы объявили префикс пространства имен, ваш XPath можно записать, чтобы использовать его:

/i:IntuitResponse/i:QueryResponse

Поражение пространств имен в XPath (не рекомендуется)

Альтернативой является запись предикатов, которые проверяют на local-name():

/*[local-name()='IntuitResponse']/*[local-name()='QueryResponse']/@startPosition

Или, в XPath 2.0:

/*:IntuitResponse/*:QueryResponse/@startPosition

Пространство имен в этом стиле работает, но не рекомендуется, потому что оно

  • Под-указывает полное имя элемента / атрибута.
  • Не удается различать имена элементов / атрибутов в разных пространствах имен (сама цель пространств имен). Обратите внимание, что эту проблему можно решить, добавив дополнительный предикат, чтобы проверить URI пространства имен явно1:
    /*[    namespace-uri()='http://schema.intuit.com/finance/v3' 
       and local-name()='IntuitResponse']
    /*[    namespace-uri()='http://schema.intuit.com/finance/v3' 
       and local-name()='QueryResponse']
    /@startPosition
    
    1Подается Даниэль Хейли для примечания namespace-uri().
  • Является чрезмерно подробным .
15
ответ дан kjhughes 15 August 2018 в 16:58
поделиться
  • 1
    Спасибо за такой полный ответ. Одна вещь, которую я до сих пор не понимаю, - это то, как я использую библиотеку, такую ​​как Javax или Pugi XML, для синтаксического анализа XML выше с указанным вами путем, я действительно получаю результаты (т. Е. Список узлов). У некоторых из этих библиотек есть способность как-то вывести простые пространства имен? – Adam 25 November 2016 в 18:42
  • 2
    Я думаю, что он просто игнорирует пространства имен. Если я использую /IntuitResponse/QueryResponse/Bill/Id без регистрации пространства имен, pugi / javax извлекает all Id s в документе. – Adam 25 November 2016 в 20:02
  • 3
    pugi: декларация несоответствия в документах + наблюдение за нечетным поведением = поворот и запуск / жизнь слишком коротки. Javax: Не забудьте вызвать setNamespaceAware(true) на DocumentBuilderFactory. – kjhughes 25 November 2016 в 20:56
  • 4
    Оказывается, pugixml вообще не поддерживает пространства имен xml ( stackoverflow.com/questions/1042855/… ). Включение и выключение. – Adam 25 November 2016 в 22:10
  • 5
    @DougGlancy: Извините, VBA был одним из немногих примеров, которые я еще не представил. Исправлено добавлением. Обратите внимание, что имена неквалифицированных атрибутов не помещаются автоматически в пространство имен по умолчанию, указанное в элементах предка. Я снова открыл ваш другой вопрос, не так подробно, вы уже правильно определили пространства имен. Сообщите мне здесь, если я могу вообще помочь с XPath и пространствами имен или над вашим вопросом, если это относится к этой проблеме. Благодарю. – kjhughes 20 November 2017 в 05:09
Другие вопросы по тегам:

Похожие вопросы: