Почему мой запрос XPath к XML-файлу в сети не работает? - PullRequest
0 голосов
/ 26 ноября 2009

Существует XML-файл с курсами обмена http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml:

<gesmes:Envelope>
  <gesmes:subject>Reference rates</gesmes:subject>
  <gesmes:Sender>
    <gesmes:name>European Central Bank</gesmes:name>
  </gesmes:Sender>
  <Cube>
    <Cube time="2009-11-26">
      <Cube currency="USD" rate="1.5071"/>
       ...

Я делаю следующий запрос XPath:

var doc = new XmlDocument();
doc.Load(url);
var node = doc.SelectSingleNode("//Cube[@currency=\"USD\""]);
var value = node.Attributes["rate"].Value;

но возвращается null! Где моя ошибка?

Если я сделаю этот запрос, все работает нормально:

var node = dic.SelectSingleNode("//*[@currency=\"USD\"]");
var name = node.Name; // "Cube"

Ответы [ 3 ]

5 голосов
/ 26 ноября 2009

Проблема в пространстве имен. Если вы можете использовать LINQ to XML, вы можете выразить этот запрос довольно легко. В противном случае, это немного сложнее - вы бы хотели что-то вроде этого:

var doc = new XmlDocument();
doc.Load(url);
XPathNavigator navigator = doc.CreateNavigator();    
XmlNamespaceManager nsMgr = new XmlNamespaceManager(nav.NameTable);
nsMgr.AddNamespace("gesmes", "http://www.gesmes.org/xml/2002-08-01");
nsMgr.AddNamespace("ns0", "http://www.ecb.int/vocabulary/2002-08-01/eurofxref");

var node = doc.SelectSingleNode("//ns0:Cube[@currency=\"USD\""], nsMgr);
var value = node.Attributes["rate"].Value;

(На самом деле вам не нужно пространство имен gesmes в менеджере, но вам будет проще, если вам понадобится поискать другие элементы.)

РЕДАКТИРОВАТЬ: Питер Мюррей-Раст ответ является хорошей альтернативой здесь - какой подход вы выберете, зависит от того, насколько конкретно вы хотите, чтобы элемент мог найти. Если вам нужно только пространство имен для одного запроса, имеет смысл включить URI непосредственно в XPath; если он понадобится вам больше, вы получите более сжатые запросы с помощью менеджера пространства имен.

4 голосов
/ 26 ноября 2009

Попробуйте

var node = doc.SelectSingleNode("//*[local-name()='Cube' and @currency=\"USD\""]);

вы всегда можете добавить в пространство имен, если вы его знаете

var node = doc.SelectSingleNode("//*[local-name()='Cube' and 
     namespace-uri()='http://www.ecb.int/vocabulary/2002-08-01/eurofxref' and
     @currency=\"USD\""]);

Несмотря на то, что это длинновато, я предпочитаю пытаться отсортировать префиксы пространства имен. И это также позволяет избежать проблемы пространства имен по умолчанию (xmlns="")

2 голосов
/ 28 ноября 2009

XPathVisualizer может быть удобно. Это бесплатно. Он бы не сказал вам использовать пространство имен, но это поместило бы пространство имен перед вами в пользовательском интерфейсе, и это позволило бы вам протестировать кучу альтернатив, очень быстро.

alt text

...