C# 在C中使用LINQ将XML解析为类#
我在将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>
- 1财产
- 1物业可以有多个建筑物
- 每栋建筑可以有多个租户
<?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()
};