【问题标题】:Parse XML at different levels在不同级别解析 XML
【发布时间】:2017-08-19 15:50:45
【问题描述】:

我有下面的 XML,其中预测有很多“时间”节点......超过 20 个,我只留下 3 个作为下面的示例。 我能够返回位置数据以及时间属性,但我在降水和云方面遇到了困难。

<weatherdata>
    <location>
      <name>Tokyo</name>
      <country>JP</country>
    </location>
    <forecast>
      <time from="2017-08-19T12:00:00" to="2017-08-19T15:00:00">   
          <precipitation unit="3h" value="0.1925" type="rain"/>   
          <clouds value="overcast clouds" all="88" unit="%"/>
      </time>
      <time from="2017-08-19T15:00:00" to="2017-08-19T18:00:00">
        <precipitation unit="3h" value="0.085000000000001" type="rain"/>
        <clouds value="overcast clouds" all="92" unit="%"/>
      </time>
      <time from="2017-08-19T18:00:00" to="2017-08-19T21:00:00">
        <precipitation unit="3h" value="0.7125" type="rain"/>
        <clouds value="overcast clouds" all="88" unit="%"/>
      </time>
    </forecast>
</weatherdata>

我在下面的代码中将我的问题(我知道的问题!)所在的位置标记为 C# 注释。

using (respStream = resp.GetResponseStream())
{
    location = new WeatherData.Location.LocationData();

    XmlDocument xml = Utility.retrieveXMLDocFromResponse(respStream, "/weatherdata");
    location.country = xml.GetElementsByTagName("country")[0].InnerText;
    location.name = xml.GetElementsByTagName("name")[0].InnerText;

    forecastList = new List<WeatherData.Forecast.Time>();                       
    XmlNodeList xnlNodes = xml.DocumentElement.SelectNodes("/weatherdata/forecast");
    foreach (XmlNode xndNode in xnlNodes)
    {
        WeatherData.Forecast.Time time = new WeatherData.Forecast.Time();
        time.from = xndNode["time"].GetAttribute("from");
        time.to = xndNode["time"].GetAttribute("to");                  

        // Here I am able to get data for clouds and preciptation, but the loop goes through all the 20 nodes.  I just want to return the "preciptation" and "clouds" of the relevant "time" node.
        XmlNodeList xnlTNodes = xml.DocumentElement.SelectNodes("/weatherdata/forecast/time");
        foreach (XmlNode xmlTimeNode in xnlTNodes)
        {
            time.clouds = xmlTimeNode["clouds"].GetAttribute("value");
            time.precipitation = xmlTimeNode["precipitation"].GetAttribute("type");
        }
        forecastList.Add(time);
    }
}

WeatherData 类仅包含用于存储数据的 getter/setter 方法。下面我的其他两个引用方法做同样的事情,但一个返回一个 XmlNodeList,另一个返回一个 XML 文档。
它们是静态的,所以我暂时不创建对该类的引用:

 public static XmlNodeList retrieveXMLResponse(Stream stream, String baseNode)
{
    StreamReader reader = null;
    XmlElement xelRoot = null;
    XmlNodeList xnlNodes = null;

    try
    {
        reader = new StreamReader(stream, Encoding.UTF8);
        string responseString = reader.ReadToEnd();
        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.LoadXml(responseString);

        xelRoot = xmlDoc.DocumentElement;
        xnlNodes = xelRoot.SelectNodes(baseNode);
    }
    finally
    {
        reader.Close();
    }

    return xnlNodes;
}

public static XmlDocument retrieveXMLDocFromResponse(Stream stream, String baseNode)
{
    StreamReader reader = null;
    XmlDocument xmlDoc = null;

    try
    {
        reader = new StreamReader(stream, Encoding.UTF8);
        string responseString = reader.ReadToEnd();
        xmlDoc = new XmlDocument();
        xmlDoc.LoadXml(responseString);
    }
    finally
    {
        reader.Close();   
    }

    return xmlDoc;
}

【问题讨论】:

  • 在您的代码中什么不起作用?选择所有时间节点然后访问它的时间节点似乎可以。你还想做什么?只需不要选择第 10 行中的预测节点。

标签: c# xml parsing


【解决方案1】:

正如我在评论中建议的那样,不要选择 forecast 节点,而是迭代时间节点。

using (respStream = resp.GetResponseStream())
{
    location = new WeatherData.Location.LocationData();

    XmlDocument xml = Utility.retrieveXMLDocFromResponse(respStream, "/weatherdata");
    location.country = xml.GetElementsByTagName("country")[0].InnerText;
    location.name = xml.GetElementsByTagName("name")[0].InnerText;

    forecastList = new List<WeatherData.Forecast.Time>();                       
    XmlNodeList xnlTNodes = xml.DocumentElement.SelectNodes("/weatherdata/forecast/time");
    foreach (XmlNode xmlTimeNode in xnlTNodes)
    {

        WeatherData.Forecast.Time time = new WeatherData.Forecast.Time();
        time.from = xmlTimeNode .GetAttribute("from");
        time.to = xmlTimeNode .GetAttribute("to");                           
        time.clouds = xmlTimeNode["clouds"].GetAttribute("value");
        time.precipitation = xmlTimeNode["precipitation"].GetAttribute("type");
         forecastList.Add(time);
     }

}

【讨论】:

  • 嗨@Thomas,是的,听起来很简单,除了你不能使用 xmlTimeNode.GetAttribute,它不在选项中。相反,如果您使用 xmlTimeNode["time"].GetAttribute("from") 您会得到“对象引用未设置为实例对象”...
  • @Dragonfly:你可以开始使用XmlElement 而不是XmlNode,然后使用xmlTimeNode.Attributes["from"].Value。我不知道你从哪里得到 GetAttribute() 方法。恕我直言,它不是 Microsoft 库的一部分。
【解决方案2】:

我喜欢使用 xml linq:

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 FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XDocument doc = XDocument.Load(FILENAME);

            var weather = doc.Elements("weatherdata").Select(x => new {
                name = (string)x.Descendants("name").FirstOrDefault(),
                country = (string)x.Descendants("country").FirstOrDefault(),
                forecasts = x.Descendants("time").Select( y => new {
                    from = (DateTime)y.Attribute("from"),
                    to = (DateTime)y.Attribute("to"),
                    precipitation = y.Descendants("precipitation").Select(z => new {
                        unit = (string)z.Attribute("unit"),
                        value = (float)z.Attribute("value"),
                        type = (string)z.Attribute("type")
                    }).FirstOrDefault(),
                    clouds = y.Descendants("clouds").Select(z => new {
                        value = (string)z.Attribute("value"),
                        all = (int)z.Attribute("all"),
                        unit = (string)z.Attribute("unit")
                    }).FirstOrDefault()
                }).ToList()
            }).FirstOrDefault();
        }
    }
}

【讨论】:

  • 我不确定 OP 是否想要一个消除 100% 自己代码的答案。他也可以尝试使用 JQuery。
猜你喜欢
  • 2012-07-02
  • 1970-01-01
  • 1970-01-01
  • 2019-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多