我只是想了解Linq并且我正在尝试做一些看似非常简单的事情,但我无法按照我想要的方式输出它。我已经坚持了几天尝试各种不同的方法,我只是无法正确。
所以我有一个类EarObs,它有成员:eventID,icaoId,frm,sta,db。
我正在尝试从List构建XML文档。我希望XML文档看起来像这样:
<EarObs EventId = "123456789">
<icao icaoID = "0001">
<frm frm = "01">
<sta sta = "00">
<db>87</db>
<hz>99</hz>
</sta>
<sta station = "01">
<db>79</db>
<hz>99</hz>
</sta>
</frm>
<frm frm = "02">
................
</frm>
</icao>
</EarObs>
如果有多个帧或多个代码等,这将继续保持相同的顺序。
所以这就是我最近一直在尝试的,但它仍然没有按照我想要的方式输出,Obs重复,我不知道我哪里出错了。
string eventGUID = "eventGUID";
List<EarObs> frameObsList = new List<EarObs>();
for (int frm = 2; frm > 0; frm--)
{
for (int sta = 5; sta > 0; sta--)
{
frameObsList.Add(new EarObs("KAPF", eventGUID, frm, sta, 85 + sta, 99 + sta));
cnt++;
}
}
String eventID = obsList.First().EventGUID;
List<EarObs> distinctApts =
obsList
.GroupBy(p => p.IcaoId)
.Select(g => g.First())
.ToList();
XElement xElement = new XElement("EarObs", new XAttribute("eventID", eventID),
from ea in distinctApts
orderby ea.IcaoId
select new XElement("icao", new XAttribute("code", ea.IcaoId),
from eb in obsList
where ea.IcaoId == eb.IcaoId
orderby eb.Frm
select new XElement("frm", new XAttribute("frm", eb.Frm),
from ec in obsList
where eb.Frm == ec.Frm
orderby ec.Sta
select new XElement("sta", new XAttribute("sta", ec.Sta),
new XElement("db", ec.Db),
new XElement("hz", ec.Hz)))));
使用此代码,我得到一个xml文档,为每个站重复一次帧。这是不正确的。我觉得这很容易顺序完成,但我正在努力学习,这似乎很简单,我应该能够在Linq中做到这一点。我需要列表中的每个元素只在XML文档中表示一次。我该怎么做?
我还想扩展它,以便它可以处理多个eventId,但这并不像正确的XML结构那么重要。任何帮助都会非常感激,我还没有找到太多创建XML的例子,包括使用linq过滤元素,大多数例子似乎都在创建XML之前就已经准备好了List。
答案 0 :(得分:1)
由于你有一个自定义类,EarObs为什么不为你的对象定义Xml属性并使用XmlSerlizer类序列化对象?这样,您可以继续在对象上使用Linq,也可以输出对象。
e.g。以下是一个团队,其中有玩家。
[XmlRoot("root")]
public class Team
{
private List<Player> players = new List<Player>();
[XmlElement("player")]
public List<Player> Players { get { return this.players; } set { this.players = value; } }
// serializer requires a parameterless constructor class
public Team() { }
}
public class Player
{
private List<int> verticalLeaps = new List<int>();
[XmlElement]
public string FirstName { get; set; }
[XmlElement]
public string LastName { get; set; }
[XmlElement]
public List<int> vertLeap { get { return this.verticalLeaps; } set { this.verticalLeaps = value; } }
// serializer requires a parameterless constructor class
public Player() { }
}
一旦我创建了一个团队,其中有一些玩家,我就必须这样做:
Team myTeamData = new Team();
// add some players on it.
XmlSerializer deserializer = new XmlSerializer(typeof(Team));
using (TextReader textReader = new StreamReader(@"C:\temp\temp.txt"))
{
myTeamData = (Team)deserializer.Deserialize(textReader);
textReader.Close();
}
输出将如下所示:
<?xml version="1.0" encoding="utf-8"?>
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<player>
<FirstName>dwight</FirstName>
<LastName>howard</LastName>
<vertLeap>1</vertLeap>
<vertLeap>2</vertLeap>
<vertLeap>3</vertLeap>
</player>
<player>
<FirstName>dwight</FirstName>
<LastName>howard</LastName>
<vertLeap>1</vertLeap>
</player>
</root>
答案 1 :(得分:0)
最简单的方法是创建一组类来处理序列化,就像这样;
public class sta
{
public int db { get; set; }
public int hz { get; set; }
[XmlAttribute()]
public string station { get; set; }
}
public class frm
{
[XmlAttribute("frm")]
public string frmID { get; set; }
[XmlElement("sta")]
public List<sta> stas { get; set; }
}
public class icao
{
[XmlAttribute]
public string icaoID { get; set; }
[XmlElement("frm")]
public List<frm> frms { get; set; }
}
public class EarObs
{
[XmlAttribute]
public string EventId { get; set; }
[XmlElement("icao")]
public List<icao> icaos { get; set; }
}
您可以使用xml序列化程序来序列化/反序列化。以下序列化为与您拥有的结构相同的结构;
XmlSerializer serializer = new XmlSerializer(typeof(EarObs));
EarObs obs = new EarObs() { EventId = "123456789" };
obs.icaos = new List<icao>();
obs.icaos.Add(new icao() { icaoID = "0001" });
obs.icaos[0].frms = new List<frm>();
obs.icaos[0].frms.Add(new frm() { frmID = "01" });
obs.icaos[0].frms[0].stas = new List<sta>();
obs.icaos[0].frms[0].stas.Add(new sta() { station = "00", db = 87, hz = 99 });
obs.icaos[0].frms[0].stas.Add(new sta() { station = "01", db = 79, hz = 99 });
obs.icaos[0].frms.Add(new frm() { frmID = "02" });
using (StringWriter s = new StringWriter())
{
serializer.Serialize(s, obs);
string test = s.ToString();
}
输出;
<?xml version="1.0" encoding="utf-16"?>
<EarObs xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" EventId="123456789">
<icao icaoID="0001">
<frm frm="01">
<sta station="00">
<db>87</db>
<hz>99</hz>
</sta>
<sta station="01">
<db>79</db>
<hz>99</hz>
</sta>
</frm>
<frm frm="02" />
</icao>
</EarObs>
现在,虽然这看起来很麻烦,但是可以使用xsd.exe工具(我相信的框架附带),自动创建一组匹配任何给定xml文件的类,尽管它确实使用中间的xsd文件(虽然无痛)。你可以在这里找到方法; How to generate .NET 4.0 classes from xsd?