Ответ 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";
// ...
}
});
- Не забудьте вызвать
DocumentBuilderFactory.setNamespaceAware(true)
. - См. Также: Java XPath: запросы с пространством имен по умолчанию xmlns.
XMLStarlet:
-N i="http://schema.intuit.com/finance/v3"
JavaScript:
Посмотрите Реализацию Определителя, определяемого пользователем пространства имен:
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:
Адаптировано из ответа @Tomalak с использованием 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");
Смотрите также @IMSoP canonical Q/A в пространствах имен PHP SimpleXML.
С#:
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("i", "http://schema.intuit.com/finance/v3");
XmlNodeList nodes = el.SelectNodes(@"/i:IntuitResponse/i:QueryResponse", nsmgr);
VBA:
xmlNS = "xmlns:i='http://schema.intuit.com/finance/v3'"
doc.setProperty "SelectionNamespaces", xmlNS
Set queryResponseElement =doc.SelectSingleNode("/i:IntuitResponse/i:QueryResponse")
VB.NET:
xmlDoc = New XmlDocument()
xmlDoc.Load("file.xml")
nsmgr = New XmlNamespaceManager(New XmlNameTable())
nsmgr.AddNamespace("i", "http://schema.intuit.com/finance/v3");
nodes = xmlDoc.DocumentElement.SelectNodes("/i:IntuitResponse/i:QueryResponse",
nsmgr)
Рубин (Нокогири):
puts doc.xpath('/i:IntuitResponse/i:QueryResponse',
'i' => "http://schema.intuit.com/finance/v3")
Обратите внимание, что Nokogiri поддерживает удаление пространств имен,
doc.remove_namespaces!
но посмотрите нижеприведенные предупреждения, препятствующие победе пространств имен XML.
После того, как вы объявили префикс пространства имен, ваш 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()
. -
Это слишком многословно.