XML和LINQ [英] XML & LINQ
问题描述
<br />
<pre lang="xml"><?xml version="1.0" encoding="utf-8"?><br />
<Controllers><br />
<PLC ConfigName="OP010"><br />
<IPAddress>172.21.1.1</IPAddress><br />
<SubnetMask>255.255.255.0</SubnetMask><br />
<ENxT_Slot>1</ENxT_Slot><br />
<CPU_Slot>0</CPU_Slot><br />
<ProgName>OP010_ePRESS</ProgName><br />
<CurveTag>Curve</CurveTag><br />
<CommTimeOut>1000</CommTimeOut><br />
<UpdateRate>250</UpdateRate><br />
</PLC><br />
<PLC ConfigName="OP020"><br />
<IPAddress>172.21.1.2</IPAddress><br />
<SubnetMask>255.255.254.0</SubnetMask><br />
<ENxT_Slot>1</ENxT_Slot><br />
<CPU_Slot>0</CPU_Slot><br />
<ProgName>OP020_ePRESS</ProgName><br />
<CurveTag>Curve</CurveTag><br />
<CommTimeOut>1000</CommTimeOut><br />
<UpdateRate>250</UpdateRate><br />
</PLC><br />
</Controllers></pre><br />
<br />
我在VS2010和C#上使用XML在LINQ上大吃一惊.使用上面显示的XML,我得到了以下代码,以这种方式将XElements从XML中拉出
I''m taking a swag at LINQ with XML with VS2010 and C#. Using the XML shown above, I''ve got the following code to pull the XElements out of the XML this way -
<br />
<pre lang="cs">var xmlElemList = from xmlElements in XElement.Load(@"configuration.xml").Elements("PLC") select xmlElements;<br />
<br />
foreach (var xmlElem in xmlElemList)<br />
{</pre><br />
我可以使用foreach遍历每个元素,也可以将内容打印到控制台.我可以从< plc configname ="OPxxx">中拉出该属性.我不知道该怎么做的是1)将数据映射到我拥有的具有相同名称属性的类对象中,或者至少2)分配每个< plc配置名称的后代... =">变量,而无需使用非常痛苦的过程(例如我在下面发布的过程).必须有一种更简单的方法.
以下是有效的方法(丑陋!!!)-
为每组数据创建一组定界符-
I can iterate through each element with a foreach, I can print the contents to the console. I can pull out the attribute from the <plc configname="OPxxx">. What I can''t figure out how to do is either 1) Map the data into a class object I have with properties of the same name, or at the very least 2) assign the descendants of each <plc configname...=""> to variables without using a very painful process such as what I post below. There has got to be an easier way.
What does work (UGLY!!!) is the following -
Create a set of delimiters for each set of data -
<br />
<pre lang="cs">String[] ip_addr_delim = new String[2] { "</IPAddress>", "<IPAddress>" };<br />
String[] sub_net_delim = new String[2] { "<SubnetMask>", "</SubnetMask>" };<br />
String[] comm_slot_delim = new String[2] { "<ENxT_Slot>", "</ENxT_Slot" };<br />
String[] cpu_slot_delim = new String[2] { "<CPU_Slot>", "</CPU_Slot>" };<br />
String[] prog_name_delim = new String[2] { "<ProgName>", "</ProgName>" };<br />
String[] curve_tag_delim = new String[2] { "<CurveTag>", "</CurveTag>" };<br />
String[] timeout_delim = new String[2] { "<CommTimeOut>", "</CommTimeOut>" };<br />
String[] update_rate_delim = new String[2] { "<UpdateRate>", "</UpdateRate>" };</pre><br />
然后遍历它们,创建一个PLC类对象,分配值,然后添加..rinse并重复.我不敢相信没有比这更优雅的解决方案了.
Then iterate through them all, creating a PLC class object, assigning values, then adding..rinse and repeat. I can''t believe there isn''t a much more elegant solution.
<br />
<pre lang="cs">// Execute the query<br />
foreach (var xmlElem in xmlElemList)<br />
{<br />
string[] temp;<br />
<br />
ActiveCfg.ConfigName = xmlElem.FirstAttribute.Value.ToString();<br />
<br />
temp = xmlElem.ToString().Split(ip_addr_delim, StringSplitOptions.RemoveEmptyEntries);<br />
ActiveCfg.IPAddress = temp[1];<br />
<br />
temp = xmlElem.ToString().Split(sub_net_delim, StringSplitOptions.RemoveEmptyEntries);<br />
ActiveCfg.SubnetMask = temp[1];<br />
<br />
temp = xmlElem.ToString().Split(comm_slot_delim, StringSplitOptions.RemoveEmptyEntries);<br />
ActiveCfg.ENxT_Slot = Convert.ToByte(temp[1]);<br />
<br />
temp = xmlElem.ToString().Split(cpu_slot_delim, StringSplitOptions.RemoveEmptyEntries);<br />
ActiveCfg.CPU_Slot = Convert.ToByte(temp[1]);<br />
<br />
temp = xmlElem.ToString().Split(prog_name_delim, StringSplitOptions.RemoveEmptyEntries);<br />
ActiveCfg.ProgName = temp[1];<br />
<br />
temp = xmlElem.ToString().Split(curve_tag_delim, StringSplitOptions.RemoveEmptyEntries);<br />
ActiveCfg.CurveTag = temp[1];<br />
<br />
temp = xmlElem.ToString().Split(timeout_delim, StringSplitOptions.RemoveEmptyEntries);<br />
ActiveCfg.CommTimeOut = Convert.ToInt32(temp[1]);<br />
<br />
temp = xmlElem.ToString().Split(update_rate_delim, StringSplitOptions.RemoveEmptyEntries);<br />
ActiveCfg.UpdateRate = Convert.ToInt32(temp[1]);<br />
<br />
PLC_List.Add(this.ActiveCfg);<br />
<br />
}</pre><br />
我应该补充一点,我可以自由更改.XML中的XML格式以适应我的需要,因此,如果在不违反XML规则的情况下使事情变得更容易,我可以接受.
I should add that I am free to change the XML format in the .XML to fit my needs so if that makes something easier without breaking rules of XML, I''m open to it.
推荐答案
一个测试项目中的一些复制粘贴代码:
它既旧又丑,但是:看一下"Value"属性;)
some copy paste code from a test project:
it''s old and ugly, but: Have a look at the "Value" property ;)
XDocument xmlDoc = XDocument.Load(fileName);
try
{
//
//
// get origins from project file
var Origins = from Origin in xmlDoc.Descendants("Origin")
select new
{
name = Origin.Element("Name").Value,
tx = Origin.Element("X").Value,
ty = Origin.Element("Y").Value,
tz = Origin.Element("Z").Value,
id = Origin.Element("ID").Value,
};
foreach (var tmp in Origins)
{
// create new origin object
OriginObject origin = new OriginObject();
origin.X = double.Parse(tmp.tx);
origin.Y = double.Parse(tmp.ty);
origin.Z = double.Parse(tmp.tz);
origin.ID = int.Parse(tmp.id);
origin.Name = tmp.name;
// add the origin to the collection
this.OriginsCollection.Add(origin.Name, origin);
}
}
catch(Exception e)
{
System.Diagnostics.Debug.Print(
"Error while reading:{0}\n{1}", e.Message, e.StackTrace);
}
非常感谢!我只是通过将我在MSDN上看到的几件事放在一起,才发现这样做似乎是一种不错的方法.我知道我今天至少看过同一页5次...可能有一种更简洁的方法,但这似乎效果很好-
Thanks much for the answer! I just figured out what appears to be a nice way to do it by putting together a couple of things I saw on MSDN. I know I looked at the same page at least 5 times today... There may be a cleaner way, but this seems to work well -
<br />
<pre lang="xml">// Create the query<br />
var xmlElemList = from xmlElements<br />
in XElement.Load(@"configuration.xml").Elements("PLC")<br />
select xmlElements;<br />
<br />
foreach (var xmlElem in xmlElemList.OfType<XElement>())<br />
{<br />
cPLC plc = new cPLC();<br />
plc.ConfigName = (string)xmlElem.FirstAttribute.Value;<br />
plc.IPAddress = (string)xmlElem.Element("IPAddress");<br />
plc.SubnetMask = (string)xmlElem.Element("SubnetMask");<br />
plc.CommSlot = (Int32)xmlElem.Element("CommSlot");<br />
plc.CpuSlot = (Int32)xmlElem.Element("CpuSlot");<br />
plc.ProgName = (string) xmlElem.Element("ProgName");<br />
plc.CurveTag = (string) xmlElem.Element("CurveTag");<br />
plc.CommTimeOut = (Int32) xmlElem.Element("CommTimeOut");<br />
plc.UpdateRate = (Int32) xmlElem.Element("UpdateRate");<br />
plcList.Add(plc);<br />
}</pre><br />
<br />
有一种更简单的方法.
There is an easier way.
XDocument xmlDoc = XDocument.Load(path);
var videos = from video in xmlDoc.Descendants("video")
select new
{
FilePath = video.Attribute("filepath").Value,
ThumbPath = video.Attribute("thumbpath").Value,
RolloverPath = video.Attribute("rolloverimage").Value,
Index = Convert.ToInt32(video.Attribute("index").Value),
Title = video.Attribute("title").Value,
IsDog = Convert.ToBoolean(video.Attribute("isdog").Value),
IsCat = Convert.ToBoolean(video.Attribute("iscat").Value),
IsHorse = Convert.ToBoolean(video.Attribute("ishorse").Value)
};
这段代码将创建具有我命名的属性的对象的集合.现在,我可以对其进行迭代,并使用它在代码中设置强类型/命名类的值.
This code will create a collection of objects with the properties I name. Now I can iterate over that and use it to set the values of my strongly typed/named class in my code.
这篇关于XML和LINQ的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!