C# менеджер пространства имен не работает при разборе XML с пространством имен - PullRequest
1 голос
/ 16 января 2020

Я пытаюсь проанализировать XML из этого URL , приведенного ниже, в C#:

<?xml version="1.0" encoding="UTF-8"?>
<gesmes:Envelope xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01"
                 xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref">
    <gesmes:subject>Reference rates</gesmes:subject>
    <gesmes:Sender>
        <gesmes:name>European Central Bank</gesmes:name>
    </gesmes:Sender>
    <Cube>
        <Cube time='2020-01-16'>
            <Cube currency='USD' rate='1.1169'/>
            <Cube currency='JPY' rate='122.80'/>
            <Cube currency='BGN' rate='1.9558'/>
        </Cube>
    </Cube>
</gesmes:Envelope>

Это код, который я использую для получения валют:

xml.Load(@"https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml");
XmlNamespaceManager ns = new XmlNamespaceManager(xml.NameTable);
ns.AddNamespace("gesmes", "http://www.ecb.int/vocabulary/2002-08-01/eurofxref");

XmlNodeList nodes = xml.DocumentElement.SelectNodes("/gesmes:Envelope/Cube/Cube/Cube", ns);
foreach (XmlNode node in nodes)
{
  // some code here
}

Однако nodes всегда null. Я перепробовал множество вариантов, и единственная возможность, с которой он работал, заключалась в удалении пространства имен из исходного XML. Но я бы хотел разобрать исходный код без изменений.

Ответы [ 3 ]

1 голос
/ 16 января 2020

Существует три проблемы, которые нужно исправить:

  1. Вы неправильно определили пространство имен, связанное с gesmes.

    Измените

    ns.AddNamespace("gesmes", "http://www.ecb.int/vocabulary/2002-08-01/eurofxref");
    

    на

    ns.AddNamespace("gesmes", "http://www.gesmes.org/xml/2002-08-01");
    
  2. Ваш XPath не учитывает, что Cube и его потомки находятся в пространстве имен по умолчанию.

    Создайте префикс для пространства имен по умолчанию:

    ns.AddNamespace("eu", "http://www.ecb.int/vocabulary/2002-08-01/eurofxref");
    
  3. Обновите свой XPath с префиксом пространства имен из # 2:

    /gesmes:Envelope/eu:Cube/eu:Cube/eu:Cube
                     ^^^     ^^^     ^^^
    

    (Cube в кубе? ?)

После устранения вышеуказанных проблем ваш код должен работать как положено.

0 голосов
/ 16 января 2020

Я только что написал тот же код для кого-то в прошлом месяце. Используйте словарь

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        const string URL = "https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml";
        static void Main(string[] args)
        {
            XDocument doc = XDocument.Load(URL);
            XNamespace ns = doc.Root.GetDefaultNamespace();

            Dictionary<string, decimal> dict = doc.Descendants(ns + "Cube").Where(x => x.Attribute("currency") != null)
                .GroupBy(x => (string)x.Attribute("currency"), y => (decimal)y.Attribute("rate"))
                .ToDictionary(x => x.Key, y => y.FirstOrDefault());
        }
    }


}
0 голосов
/ 16 января 2020

Линк XML всегда давал мне меньше головной боли:

var doc = XDocument.Load("https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml");
string ns = "http://www.ecb.int/vocabulary/2002-08-01/eurofxref";

var outerCube = doc.Root.Element(XName.Get("Cube", ns));
var timeCube = outerCube.Element(XName.Get("Cube", ns));

Console.WriteLine("Time: " + timeCube.Attribute("time").Value);

foreach (var cube in timeCube.Elements())
{
    Console.WriteLine(cube.Attribute("currency").Value + " => " + cube.Attribute("rate"));
}
...