Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/305.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 解析XML和创建对象的更好方法?_C#_.net_Xml_Xml Parsing - Fatal编程技术网

C# 解析XML和创建对象的更好方法?

C# 解析XML和创建对象的更好方法?,c#,.net,xml,xml-parsing,C#,.net,Xml,Xml Parsing,我目前正在学习如何用C处理XML,并尝试从以下url解析和创建一个对象: 函数调用 解析 代码可以工作,但效率似乎有点低,因为我返回了一个必须使用的IEnumerable。使用这段代码,我也无法获得其他时间元素,其中from=和to=属性与该小时的预测相同,我希望获得至少未来三个小时的小时预测 我曾尝试使用xsd.exe从模式创建一个类,但这毫无意义,因此目前我坚持使用LocationForecast类 是否有一种更有效的方法来执行此解析,并获得下一个每小时的预测?如果您不想处理XDocumen

我目前正在学习如何用C处理XML,并尝试从以下url解析和创建一个对象:

函数调用

解析

代码可以工作,但效率似乎有点低,因为我返回了一个必须使用的IEnumerable。使用这段代码,我也无法获得其他时间元素,其中from=和to=属性与该小时的预测相同,我希望获得至少未来三个小时的小时预测

我曾尝试使用xsd.exe从模式创建一个类,但这毫无意义,因此目前我坚持使用LocationForecast类


是否有一种更有效的方法来执行此解析,并获得下一个每小时的预测?

如果您不想处理XDocument及其元素,可以创建一个类层次结构,供XmlSerializer使用DataContractSerializer无法真正利用,因为它不支持XML属性,它将回退到XmlSerializer

好处是它将降低GetXmlData方法的复杂性。作为一个缺点,您不会得到更少的代码,而且您似乎希望值是双倍的,因此需要一些运算符魔术来支持隐式强制转换

GetXmlData 此方法现在将打开一个流并使用获取所有天气数据。获得后,它将获得Forecast集合中的第一个位置项。如果您需要其他物品,可以更改此项

public Location GetXmlData(string url)
{
    Location loc;
    using(var wc = new WebClient())
    {
        // Type you want to deserialize
        var ser = new XmlSerializer(typeof(WeatherData));
        using(var stream = wc.OpenRead(url))
        {   
            // create the object, cast the result
            var w = (WeatherData) ser.Deserialize(stream);
            // w.Dump(); // linqpad testing
            // what do we need
            loc =  w.Product.ForeCasts.First().Location;
        }
    }
    return loc;
}
反序列化类 您的XML大致如下所示:

void Main()
{
    var url = @"https://api.met.no/weatherapi/locationforecast/1.9/?lat=60.10&lon=9.58";
    var loc = GetXmlData(url);
    Double f = loc.Fog;
    f.Dump("Percent as double");
    Double t = loc.Temperature;
    t.Dump("Temperature as double");
}
特例 location中的元素都具有相似的属性,因此我创建了一个主类来捕获所有这些变化:

// covers all kind of things
public class Measurement
{
    [XmlAttribute("id")]
    public string Id {get;set;}
    [XmlAttribute("unit")]
    public string Unit {get;set;}
    [XmlAttribute("deg")]
    public double Deg {get;set;}
    [XmlAttribute("value")]
    public double Value {get;set;}
    [XmlAttribute("mps")]
    public double Mps {get;set;}
    [XmlAttribute("percent")]
    public double Percent {get;set;}
}
具体测量 您的用例似乎表明您希望使用度量的某个属性(现在是属性)的双精度。为此,我将测量分为值和百分比。这里的类实现了一个,因此它不需要为这个类的使用者进行强制转换

// for properties that use the Value attribute
public class Value:Measurement
{
    // operators for easy casting
    public static implicit operator Value(Double d) 
    {
        var v = new Value();
        v.Value = d;
        return v;
    }
    public static implicit operator Double(Value v)
    {
        return v.Value;
    }

    public override string ToString() 
    {
       return this.Value.ToString();
    }
}

// for properties that use the Percent attribute
public class Percent:Measurement
{
    // operators for easy casting
    public static implicit operator Percent(Double d) 
    {
        var p = new Percent();
        p.Percent = d;
        return p;
    }
    public static implicit operator Double(Percent p)
    {
        return p.Percent;
    }

    public override string ToString() 
    {
       return this.Percent.ToString();
    }
}
小型测试方法如下所示:

void Main()
{
    var url = @"https://api.met.no/weatherapi/locationforecast/1.9/?lat=60.10&lon=9.58";
    var loc = GetXmlData(url);
    Double f = loc.Fog;
    f.Dump("Percent as double");
    Double t = loc.Temperature;
    t.Dump("Temperature as double");
}
如果您不认为属性不是double类型,那么可以重用LocationForecast类,但在这种情况下,您需要实例化并映射自己的值,例如:

 var lf = new LocationForcast {
     Temperature = loc.Temperature,
     Precent = loc.Percent,
     // etc.
 };

或者使用像

这样的库使用XmlSerializer或DataContractSerializerI强烈建议研究如何在c中反序列化xml。您将看到如何更好地处理这个问题,在这里您可以创建一个类来表示XML,这样您的生活将更加轻松。首先选择您感兴趣的所有节点,然后创建业务对象。由于xdoc.subjects.Firstx=>stringx.Attributedatatype==forecast,目前您只获取第一个节点;而不是先。。它应该在。。。。您甚至可以将部分查询提取到方法中,以使其更具可读性。
// for properties that use the Value attribute
public class Value:Measurement
{
    // operators for easy casting
    public static implicit operator Value(Double d) 
    {
        var v = new Value();
        v.Value = d;
        return v;
    }
    public static implicit operator Double(Value v)
    {
        return v.Value;
    }

    public override string ToString() 
    {
       return this.Value.ToString();
    }
}

// for properties that use the Percent attribute
public class Percent:Measurement
{
    // operators for easy casting
    public static implicit operator Percent(Double d) 
    {
        var p = new Percent();
        p.Percent = d;
        return p;
    }
    public static implicit operator Double(Percent p)
    {
        return p.Percent;
    }

    public override string ToString() 
    {
       return this.Percent.ToString();
    }
}
void Main()
{
    var url = @"https://api.met.no/weatherapi/locationforecast/1.9/?lat=60.10&lon=9.58";
    var loc = GetXmlData(url);
    Double f = loc.Fog;
    f.Dump("Percent as double");
    Double t = loc.Temperature;
    t.Dump("Temperature as double");
}
 var lf = new LocationForcast {
     Temperature = loc.Temperature,
     Precent = loc.Percent,
     // etc.
 };