Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/14.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/5/ruby-on-rails-4/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# 在C中使用LINQ将XML解析为类#_C#_Xml_Linq_Linq To Xml - Fatal编程技术网

C# 在C中使用LINQ将XML解析为类#

C# 在C中使用LINQ将XML解析为类#,c#,xml,linq,linq-to-xml,C#,Xml,Linq,Linq To Xml,我在将XML文档解析为自定义类时遇到了很多麻烦。我试着阅读我在网上和这里能找到的东西,但我仍然没有取得任何进展。我正在开发一个房地产应用程序,并尝试对您拥有的基本房产进行建模: 1财产 1物业可以有多个建筑物 每栋建筑可以有多个租户 我决定尝试将数据存储在xml文档中,并制作了如下示例: <?xml version="1.0" encoding="UTF-8"?> <Property> <Name>Grove Center</Name>

我在将XML文档解析为自定义类时遇到了很多麻烦。我试着阅读我在网上和这里能找到的东西,但我仍然没有取得任何进展。我正在开发一个房地产应用程序,并尝试对您拥有的基本房产进行建模:

  • 1财产
  • 1物业可以有多个建筑物
  • 每栋建筑可以有多个租户
我决定尝试将数据存储在xml文档中,并制作了如下示例:

<?xml version="1.0" encoding="UTF-8"?>
<Property>
    <Name>Grove Center</Name>
    <Building>
        <Name>Building1</Name>
        <Tenant>
            <Name>Tenant1</Name>
            <SquareFeet>2300</SquareFeet>
            <Rent>34000</Rent>
        </Tenant>
        <Tenant>
            <Name>Tenant2</Name>
            <SquareFeet>3100</SquareFeet>
            <Rent>42000</Rent>
        </Tenant>
        <Tenant>
            <Name>Tenant3</Name>
            <SquareFeet>1700</SquareFeet>
            <Rent>29000</Rent>
        </Tenant>
    </Building>
    <Building>
        <Name>Building2</Name>
        <Tenant>
            <Name>Tenant1</Name>
            <SquareFeet>6150</SquareFeet>
            <Rent>80000</Rent>
        </Tenant>
        <Tenant>
            <Name>Tenant2</Name>
            <SquareFeet>4763</SquareFeet>
            <Rent>60000</Rent>
        </Tenant>
    </Building>
</Property>

感谢您的帮助,以下查询将为您提供正确的结果:-

Property p = new Property
               {
                  Name = (string)doc.Root.Element("Name"),
                  Buildings = doc.Root.Elements("Building")
                                 .Select(x => new Building
                                  {
                                     Name = (string)x.Element("Name"),
                                     Tenants = x.Elements("Tenant")
                                                .Select(t => new Tenant
                                                 {
                                                     Name = (string)t.Element("Name"),
                                                     SF = (int)t.Element("SquareFeet"),
                                                     Rent = (decimal)t.Element("Rent")
                                                 }).ToList()
                                   }).ToList()
                };

有些事情你可能想改变

属性名称必须与xml标记匹配,或者必须手动指定映射。在示例代码中,建筑物和租户声明为字段,您应该将其更改为属性。如果需要,可以在构造函数中将它们初始化为空列表:

public class Property
{
    public string Name { get; set; }
    [XmlElement("Building")]
    public List<Building> Buildings { get; set; }

    public Property()
    {
        Buildings = new List<Building>();
    }
}

public class Building
{
    public string Name { get; set; }
    [XmlElement("Tenant")]
    public List<Tenant> Tenants { get; set; }

    public Building()
    {
        Tenants = new List<Tenant>();
    }
}

public class Tenant
{
    public string Name { get; set; }
    [XmlAttribute("SquareFeet")]
    public int SF { get; set; }
    public decimal Rent { get; set; }
}
公共类属性
{
公共字符串名称{get;set;}
[XmlElement(“建筑”)]
公共列表建筑物{get;set;}
公共财产()
{
建筑物=新列表();
}
}
公共班级大楼
{
公共字符串名称{get;set;}
[XmlElement(“承租人”)]
公共列表租户{get;set;}
公共建筑()
{
租户=新列表();
}
}
公屋租户
{
公共字符串名称{get;set;}
[XmlAttribute(“平方英尺”)]
公共整数SF{get;set;}
公共十进制租金{get;set;}
}
此外,我建议反序列化文件,而不是使用linq。考虑这些辅助方法:

public static class XmlHelper
{
    public static T DeserializeFromXmlString<T>(string xml)
    {
        var xmlSerializer = new XmlSerializer(typeof (T));
        using (var stringReader = new StringReader(xml))
        {
            return (T) xmlSerializer.Deserialize(stringReader);
        }
    }

    public static T DeserializeFromXmlFile<T>(string filename) where T : new()
    {
        return DeserializeFromXmlString<T>(File.ReadAllText(filename));
    }
}
公共静态类XmlHelper
{
公共静态T反序列化FromXmlString(字符串xml)
{
var xmlSerializer=新的xmlSerializer(typeof(T));
使用(var stringReader=newstringreader(xml))
{
返回(T)xmlSerializer.Deserialize(stringReader);
}
}
公共静态T反序列化FromXmlFile(字符串文件名),其中T:new()
{
返回反序列化的FromXmlString(File.ReadAllText(filename));
}
}
反序列化很容易:

var listOfProperties = XmlHelper.DeserializeFromXmlFile<Property>(@"C:\Users\SampleUser\Desktop\sample-property.xml");
var listOfProperties=XmlHelper.DeserializeFromXmlFile(@“C:\Users\SampleUser\Desktop\sample property.xml”);

使用空列表初始化公共字段是一种很好的做法,可以避免出现错误。如果不初始化它们,则它们为空,因此会出现错误

但是,您可以使用属性来代替列表中的字段

从C#6开始,您可以使用简化的自动特性分配:

public List<Building> Buildings {get;set;} = new List<Building>();
公共列表建筑{get;set;}=new List();
对于C#<6,您可以使用自动属性并在构造函数中初始化属性,或者使用带有支持字段的属性

//Auto property with assignment in constructor
public class Property
{
    public string Name { get; set; }
    public List<Building> Buildings {get;set;};
    public Property(){
        Buildings = new List<Building>();
    }
}

//Property with backing field
public class Property
{
    private List<Building> _buildings = new List<Building>();
    public string Name { get; set; }
    public List<Building> Buildings {get {return _buildings;} set {_buildings = value;}};
}
//构造函数中具有赋值的自动属性
公共类财产
{
公共字符串名称{get;set;}
公共列表建筑物{get;set;};
公共财产(){
建筑物=新列表();
}
}
//带支持字段的属性
公共类财产
{
私有列表_建筑物=新列表();
公共字符串名称{get;set;}
公共列表建筑物{get{return{U Buildings;}集合{U Buildings=value;}};
}
为了读取XML和创建对象图,可以将LINQ与对象初始值设定项结合使用

Func<IEnumerable<XElement>, IEnumerable<Tenant>> getTenants = elements => {
    return elements.Select (e => new Tenant {
        Name = e.Element("Name").Value,
        Rent = decimal.Parse(e.Element("Rent").Value),
        SF = int.Parse(e.Element("SquareFeet").Value)
    });
};

Func<IEnumerable<XElement>, IEnumerable<Building>> getBuildings = elements => {
    return elements.Select (e => new Building{
        Name = e.Element("Name").Value,
        Tenants = getTenants(e.Elements("Tenant")).ToList()
    });
};

//xdoc is your parsed XML document
//e.g. var xdoc = XDdocument.Parse("xml contents here");
var property = new Property{
    Name = xdoc.Root.Element("Name").Value,
    Buildings = getBuildings(xdoc.Root.Elements("Building")).ToList()
};
Func getTenants=elements=>{
返回元素。选择(e=>newtenant{
名称=e.元素(“名称”).值,
租金=十进制.Parse(即元素(“租金”).Value),
SF=int.Parse(即元素(“平方英尺”).值)
});
};
Func getBuildings=元素=>{
返回元素。选择(e=>new Building{
名称=e.元素(“名称”).值,
租户=getTenants(即元素(“租户”)).ToList()
});
};
//xdoc是经过解析的XML文档
//e、 g.var xdoc=xdocument.Parse(“此处的xml内容”);
var属性=新属性{
Name=xdoc.Root.Element(“Name”).Value,
Buildings=getBuildings(xdoc.Root.Elements(“Building”)).ToList()
};

反序列化不是更好吗?问题1:格式没有错。您的格式表示该属性由多个建筑组成。另一种方法首先指定属性由多个建筑组成,然后列出它们。这两个答案都是正确的。很好的答案非常有效。来吧,接受这个。谢谢你提供的关于属性和XmlAttribute的信息。我看了两个其他的解决方案,比如XmlReader,并选择了LINQ,主要是因为它似乎是处理XML的较新技术标准(我只是想学习如何更好地使用它),感谢关于C#6和属性的信息。我必须使用较低的值,因为
public-List-Buildings{get;set;}=new-List()不是为我编译的。说实话,我对IEnumerable的东西很困惑,我从来没有很好地使用过它。我没有很多C#方面的经验,还在学习。IEnumerable只是一个由许多集合(如List)实现的接口。它公开了一个枚举数,允许您对其进行迭代(例如,使用foreach循环)。在本例中,您可以将其替换为List,然后必须在.Select()方法之后调用ToList()(我是在调用Func之后调用的)。
//Auto property with assignment in constructor
public class Property
{
    public string Name { get; set; }
    public List<Building> Buildings {get;set;};
    public Property(){
        Buildings = new List<Building>();
    }
}

//Property with backing field
public class Property
{
    private List<Building> _buildings = new List<Building>();
    public string Name { get; set; }
    public List<Building> Buildings {get {return _buildings;} set {_buildings = value;}};
}
Func<IEnumerable<XElement>, IEnumerable<Tenant>> getTenants = elements => {
    return elements.Select (e => new Tenant {
        Name = e.Element("Name").Value,
        Rent = decimal.Parse(e.Element("Rent").Value),
        SF = int.Parse(e.Element("SquareFeet").Value)
    });
};

Func<IEnumerable<XElement>, IEnumerable<Building>> getBuildings = elements => {
    return elements.Select (e => new Building{
        Name = e.Element("Name").Value,
        Tenants = getTenants(e.Elements("Tenant")).ToList()
    });
};

//xdoc is your parsed XML document
//e.g. var xdoc = XDdocument.Parse("xml contents here");
var property = new Property{
    Name = xdoc.Root.Element("Name").Value,
    Buildings = getBuildings(xdoc.Root.Elements("Building")).ToList()
};