使用linq从XML中获取一个对象数组
本文关键字:获取 一个对象 数组 XML linq 使用 | 更新日期: 2023-09-27 18:27:43
我想知道有没有一种方法可以使用Linq-to-XML从XML字符串中获取对象数组。。。我习惯于使用XPath来做我所有的脏活,而XPath似乎很直观。但是,我一直听说linq有多棒,一旦你得到了它,它就会让你的生活变得更轻松。这个问题还没有定论,但话说回来,我对林克不是很好。还在学习。但假设我有一个对象。。。
class PatientClass
{
//public int Item_ID { get; set; }
public int PatientId { get; set; }
public int EMPIID { get; set; }
}
假设我有另一个对象。。。
public class TemplateModel
{
List<PatientACOModel> Template { set; get; }
}
它只是第一个对象的列表。。。
假设我有一个xml文档,看起来像…
<dataTemplateSpecification id="id1" name="name1" >
<templates xmlns="">
<template>
<elements>
<element id="element0" name="PatientId" display="Patient ID" dataType="String" visable="true" readOnly="false" value="4563">
<mapping path="//Template/TemplateData/ACOData/PATIENT_ID" />
</element>
<element id="element1" name="PopulationPatientID" display="Population Patient ID" dataType="String" visable="true" readOnly="true" enc="2098" value="6407">
<mapping path="//Template/TemplateData/ACOData/POPULATION_PATIENT_ID" />
</element>
<element id="element2" name="EMPIID" display="EMPIID" dataType="String" visable="true" readOnly="true" value="">
<mapping path="//Template/TemplateData/ACOData/EMPI" />
</element>
</elements>
</template>
<template>
<elements>
<element id="element0" name="PatientId" display="Patient ID" dataType="String" visable="true" readOnly="false" value="4563">
<mapping path="//Template/TemplateData/ACOData/PATIENT_ID" />
</element>
<element id="element1" name="PopulationPatientID" display="Population Patient ID" dataType="String" visable="true" readOnly="true" enc="2098" value="6407">
<mapping path="//Template/TemplateData/ACOData/POPULATION_PATIENT_ID" />
</element>
<element id="element2" name="EMPIID" display="EMPIID" dataType="String" visable="true" readOnly="true" value="">
<mapping path="//Template/TemplateData/ACOData/EMPI" />
</element>
</elements>
</template>
<template>
<elements>
<element id="element0" name="PatientId" display="Patient ID" dataType="String" visable="true" readOnly="false" value="4563">
<mapping path="//Template/TemplateData/ACOData/PATIENT_ID" />
</element>
<element id="element1" name="PopulationPatientID" display="Population Patient ID" dataType="String" visable="true" readOnly="true" enc="2098" value="6407">
<mapping path="//Template/TemplateData/ACOData/POPULATION_PATIENT_ID" />
</element>
<element id="element2" name="EMPIID" display="EMPIID" dataType="String" visable="true" readOnly="true" value="">
<mapping path="//Template/TemplateData/ACOData/EMPI" />
</element>
</elements>
</template>
</templates>
</dataTemplateSpecification>
您可以看到,dataTemplateSpecification/templates/template将是上面PatientClass的一个实例。而dataTemplateSpecification/templates/将是TemplateModel对象的一个实例(PatientClass的列表……我在列表中将它们命名为PatientACOModel,但它们本质上是一样的……一个只是没有另一个那么多变量)。
现在我用它来解析一个病人对象。。。
IEnumerable<PatientClass> template = (IEnumerable<PatientClass>)(from templates in xDocument.Descendants("dataTemplateSpecification")//elem.XPathSelectElements(string.Format("//templates/template[./elements/element[@name='"PopulationPatientID'"and @value='{0}' and @enc='{1}']]", "1", 0))
select new PatientClass
{
PatientId = int.Parse(templates.Descendants("element").Single(el => el.Attribute("name").Value=="PatientId").ToString()),//XPathSelectElement("elements/element[@name='PatientId']").Attribute("value").Value),
EMPIID = int.Parse(templates.Descendants("element").Single(el => el.Attribute("name").Value=="EMPIID").ToString()),//XPathSelectElement("elements/element[@name='EMPIID']").Attribute("value").Value),
}
它目前正在返回null值,但我正在处理。。。但是我怎么能得到这些病人的名单呢。我可能需要一个超级查询来处理物品列表,而子查询来获得患者信息,对吗?
所以像这样的事情。。。
IEnumerable<TemplateModel> template = (IEnumerable<TemplateModel>)(from templates in elem.XPathSelectElements("//templates/template")
select new TemplateModel
{
TemplateModel =
(from pat in templates
select new PatientClass
{
PatientId = int.Parse(templates.XPathSelectElement("elements/element[@name='PatientId']").Attribute("value").Value),
EMPIID = int.Parse(templates.XPathSelectElement("elements/element[@name='EMPIID']").Attribute("value").Value),
)
}
这对我来说似乎是合乎逻辑的。但也许我不理解Linq
尝试一下(因为您喜欢XPath):
var s="<dataTemplateSpecification .../>";
var element = XElement.Parse(s);
var patients = element.XPathSelectElements("//elements").Select (
e => new Patient
{
PatientId = (int)e.XPathSelectElement("//element[@id='element0']").Attribute("value"),
PopulationPatientId = (int)e.XPathSelectElement("//element[@id='element1']").Attribute("value"),
EmpId = (string)e.XPathSelectElement("//element[@id='element2']").Attribute("value"),
}
);
患者类别:
class Patient{
public int PatientId{get;set;}
public int PopulationPatientId{get;set;}
public string EmpId{get;set;}
}
我们在工作中使用了手工滚动的linq到xml,所以我要试一试。
需要注意的是,所有EMPIID元素都有一个值=",这将在调用int.Parse
时导致FormatException
。XAttribute
上有一系列显式的强制转换运算符,它们可以很好地让您使用常见的.net类型。
以下是我可能为您需要进行的解析编写的代码(在不使用XPath
的情况下保持纯xnode解析风格):
IEnumerable<TemplateModel> templates =
from dataTemplate in xDocument.Descendants("dataTemplateSpecification")
select new TemplateModel
{
TemplateModel =
(from template in dataTemplate.Element("templates").Elements("template")
let elements = template.Element("elements").Elements("element")
select new PatientClass
{
PatientId = (int)elements.Single(e => (string)e.Attribute["name"] == "PatientId").Attribute("value"),
EMPIID = (int)elements.Single(e = (string)e.Attribute["name"] == "EMPIID").Attribute("value"),
}).ToList()
};
查询的类型已经是IEnumerable<TemplateModel>
,因此不需要立即强制转换结果。在大多数情况下,我倾向于简单地将类型声明为var
,但您的口味可能不同——将其保留为var
意味着,如果我应用分组或其他LINQ转换,则不必更正类型。我使用let
关键字引入了一个范围变量elements
;这对于只计算一次值并重用它很有用。由于TemplateModel
类型上TemplateModel
属性的类型是一个列表,因此我调用ToList
扩展来设置该属性。我为属性调用强制转换运算符,以将它们的值转换为int
和string
,而不是调用int.Parse
和ToString
。
LINQ的功能允许以非常优雅的方式进行进一步的处理(过滤、折叠和投影)。能够从linq到xml无缝过渡到使用linq到对象,这使得linq非常引人注目。不管怎样,来LINQ游泳池吧,水很好。:)