[英]Load and get values from XML
首先,我是 C# 的新手,但对其他编程语言有一些经验。 我现在遇到了一个我不知道如何解决的问题,所以到目前为止我还没有做任何事情,因为我真的不知道如何开始。
我有一个 XML 文件,其中包含我想匹配的数据并将其子元素存储到变量中。
例如:我想从 xml 中检索周数值为“2”的周,并将所有子元素存储到我的应用程序中的单独变量中。
<root>
<weeks>
<week weeknumber="1">
<groupNumber>1</groupNumber>
<starttime>10:00</starttime>
<startday>8</startday>
<endtime>12:00</endtime>
<endday>8</endday>
</week>
<week weeknumber="2">
<groupNumber>1</groupNumber>
<starttime>10:00</starttime>
<startday>8</startday>
<endtime>12:00</endtime>
<endday>8</endday>
</week>
<week weeknumber="3">
<groupNumber>1</groupNumber>
<starttime>10:00</starttime>
<startday>8</startday>
<endtime>12:00</endtime>
<endday>8</endday>
</week>
</weeks>
</root>
LINQ 到 XML API 自 2007 年起存在于 .Net Framework 中。
c#
void Main()
{
const string fileName = @"e:\Temp\Weeks.xml";
XDocument xdoc = XDocument.Load(fileName);
var xelem = xdoc.Descendants("week")
.Where(x => x.Attribute("weeknumber").Value.Equals("2"))
.FirstOrDefault();
int groupNumber = Convert.ToInt32(xelem.Element("groupNumber").Value);
string starTtime = xelem.Element("starttime").Value;
int startDay = Convert.ToInt32(xelem.Element("startday").Value);
string endTime = xelem.Element("endtime").Value;
int endDay = Convert.ToInt32(xelem.Element("endday").Value);
Console.WriteLine("groupNumber={0}, starTtime={1}, startDay={2}, endTime={3}, endDay={4}", groupNumber
, starTtime
, startDay
, endTime
, endDay);
}
使用 Xml 序列化然后解析结果
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication
{
public class Program
{
const string FILENAME = @"c:\temp\test.xml";
public static void Main(string[] args)
{
XmlReader reader = XmlReader.Create(FILENAME);
XmlSerializer serializer = new XmlSerializer(typeof(Root));
Root root = (Root)serializer.Deserialize(reader);
}
}
[XmlRoot("root")]
public class Root
{
[XmlArray("weeks")]
[XmlArrayItem("week")]
public List<Week> week { get; set; }
}
public class Week
{
public int groupNumber { get; set; }
private DateTime _starttime { get; set; }
public string starttime
{
get {return _starttime.ToString("HH:mm");}
set { _starttime = DateTime.ParseExact(value, "HH:mm", System.Globalization.CultureInfo.InvariantCulture); }
}
public int startday { get; set; }
private DateTime _endtime { get; set; }
public string endtime
{
get { return _endtime.ToString("HH:mm"); }
set { _endtime = DateTime.ParseExact(value, "HH:mm", System.Globalization.CultureInfo.InvariantCulture); }
}
public int endday { get; set; }
}
}
这是一种懒惰但有效的方法。 这不是目的地,而是起点。
首先,将您的 XML 粘贴到Xml2Csharp网站中。 它将生成一些与您的 XML 对应的类。 它并不总是完美的,但一旦完成,你就有了一些东西而不是一无所有,而且更容易调整一些东西。 它给了我这个:
using System;
using System.Xml.Serialization;
using System.Collections.Generic;
namespace Xml2CSharp
{
[XmlRoot(ElementName="week")]
public class Week {
[XmlElement(ElementName="groupNumber")]
public string GroupNumber { get; set; }
[XmlElement(ElementName="starttime")]
public string Starttime { get; set; }
[XmlElement(ElementName="startday")]
public string Startday { get; set; }
[XmlElement(ElementName="endtime")]
public string Endtime { get; set; }
[XmlElement(ElementName="endday")]
public string Endday { get; set; }
[XmlAttribute(AttributeName="weeknumber")]
public string Weeknumber { get; set; }
}
[XmlRoot(ElementName="weeks")]
public class Weeks {
[XmlElement(ElementName="week")]
public List<Week> Week { get; set; }
}
[XmlRoot(ElementName="root")]
public class Root {
[XmlElement(ElementName="weeks")]
public Weeks Weeks { get; set; }
}
}
我将 XML 与类一起放入单元测试项目的文件中,并创建了这个简单的单元测试。 它没有检查所有内容,但它验证 XML 被反序列化为 class 的实例,并且它包含三个“周”,就像在文件中一样。
using System.IO;
using System.Xml.Serialization;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Xml2CSharp; // the website created this namespace. You don't need to keep it.
namespace UnitTestProject1
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void Deserializes_Xml()
{
using var stream = File.OpenText("xmlfile1.xml");
var serializer = new XmlSerializer(typeof(Root));
var deserialized = (Root) serializer.Deserialize(stream);
Assert.AreEqual(3, deserialized.Weeks.Week.Count);
}
}
}
那个测试通过了。 我们克服了困难。 现在,给定一个 XML 文件,很容易将其读入一些包含所需数据的对象中。
其他一些步骤可能是重命名类(如果您关心的话)或更改某些类型。 例如,很多这些值显然是整数,但自动生成的代码不知道,所以它使用字符串。 您可以像这样更改属性:
public int GroupNumber { get; set; }
...现在您使用 integer 1 而不是字符串“1”。
现在,给定一个 class 的反序列化实例,它很容易阅读和操作。 如果您想要周数为 2 的周数,您可以写
IEnumerable<Week> weeksWithWeekNumberTwo =
deserialized.Weeks.Week.Where(w => w.Weeknumber == 2);
您可以创建更多变量,但您可能不需要。 你可以这样做:
foreach (var week in weeksWithWeekNumberTwo)
{
// each time this loop executes the "week" variable already
// has all the properties. You could assign them to more
// variables but one variable ("week") with properties is easier.
}
该方法的一个好处是它将工作的不同部分分开。 首先,您知道您正在正确阅读 XML。 如果您不确定是否可以在测试中添加更多内容。 一旦你知道你可以继续前进,忘记阅读 XML。 您只是在使用对象和属性。
现在您可以专注于查看这些类的实例并读取它们的属性的逻辑。 如果您想为此编写测试,您可以创建 class 的实例。 您不需要为不同的场景创建 XML 文件。
如果您将这些步骤混合在一起,一切都会变得更加困难,也许在您阅读文件和解析 XML 时寻找某些值。 如果你没有得到你期望的结果,哪一部分是错的? 很难判断我们是否同时做多项事情。
而且因为我们很懒,并且开始使用为我们创建类的工具,所以我们不太可能通过想知道我们是否在正确的地方使用了正确的属性而使其更加混乱。 所有这些不确定性很容易加起来长达一个小时或几个小时。 这花了几分钟。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.