在不同级别解析XML

时间:2017-08-19 15:50:46

标签: c# xml parsing

我有以下XML,在预测中有很多" time"节点...超过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#comment我的问题(我知道的那个!)是。

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

2 个答案:

答案 0 :(得分:0)

正如我的评论中提出的,只是不要选择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);
     }

}

答案 1 :(得分:0)

我喜欢使用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();
        }
    }
}