C#名称空间管理器无法使用名称空间解析XML

时间:2020-01-16 15:11:16

标签: c# xml xpath xml-namespaces

我正在尝试使用C#从下面的示例中解析this url中的XML:

{"email": "test@example.net",
"password": "aabbccdd",
"Name": "John",
}

这是我用来获取货币的代码:

<UsingTask TaskName="GetTargetFrameworkToolsFolderName" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
   <ParameterGroup>
     <SDKFolderPath ParameterType="System.String" Required="true" />
     <TargetFrameworkVersionStr ParameterType="System.String" Required="true" />
     <TargetFrameworkToolsFolder ParameterType="System.String" Output="true" />
   </ParameterGroup>
   <Task>
     <Code Type="Fragment" Language="cs">
        TargetFrameworkToolsFolder = SDKFolderPath + "\\" + "bin\\NETFX " + TargetFrameworkVersionStr.Substring(1) + " Tools\\";
     </Code>
   </Task>
</UsingTask>

<Target Name="FindTargetFrameworkToolsFolderPath" BeforeTargets="PostBuildEvent">
   <GetFrameworkSdkPath>
     <Output TaskParameter="Path" PropertyName="SdkPath" />
   </GetFrameworkSdkPath>
   <GetTargetFrameworkToolsFolderName SDKFolderPath="$(SdkPath)" TargetFrameworkVersionStr="$(TargetFrameworkVersion)">
     <Output PropertyName="TargetFrameworkToolsFolderPath" TaskParameter="TargetFrameworkToolsFolder"/>
   </GetTargetFrameworkToolsFolderName>
   <Message Text="$(TargetFrameworkToolsFolderPath)" Importance="normal" /> --> Displayed correctly here
</Target>

<PropertyGroup>
   <PostBuildEvent>
      call $(ProjectDir)AfterBuildCommands.bat $(TargetFrameworkToolsFolderPath) --> The TargetFrameworkToolsFolderPath property value here seems to be empty.
   </PostBuildEvent>
</PropertyGroup>

但是,<?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 } 。我尝试了很多选项,而对我有用的唯一选项是从原始XML中删除名称空间。但我想直接分析源代码,而不做任何修改。

3 个答案:

答案 0 :(得分:1)

有三个要纠正的问题:

  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. 使用来自#2的名称空间前缀更新您的XPath:

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

    ({Cube立方??)

解决上述问题后,您的代码应该可以按预期工作。

答案 1 :(得分:-1)

Linq 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"));
}

答案 2 :(得分:-1)

我上个月刚刚为某人编写了相同的代码。使用字典

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());
        }
    }


}