我正在尝试解析一些看起来与此类似的XML:
<document>
<headings>
Important heading stuff.
</headings>
<startGroup group="1" />
<startItem value="1" />Item one stuff<endItem />
<blockofdata>
<startItem value="2" />Item two stuff<endItem />
<startItem value="3" />Item three stuff<endItem />
</blockofdata>
<startItem value="4" />Item four stuff<endItem />
<endGroup />
<startGroup group="2" />
<startItem value="1" />Item one stuff<endItem />
<startItem value="2" />Item two stuff<endItem />
<startItem value="3" />Item three stuff<endItem />
<endGroup />
</document>
我无法找出linq-to-xml语句来获得我想要的东西。我需要弄平结构。所以假设上面的XML,我想得到一个这个POCO的列表:
class Items
{
public int GroupNumber {get;set;} // group property of startGroup
public int ItemNumber {get;set;} // value property of startItem
public string ItemText {get;set;} // data between i
}
如何编写linq-to-xml语句,在从startGroup / endGroup和startItem / endItem之间的数据中获取数据时,将属性之间的数据拉入上述项目?我已经烧了好几个小时,我准备转而使用XML流阅读器并以老式的方式解析它。
答案 0 :(得分:2)
此处的关键是使用ElementsAfterSelf()
和NodesAfterSelf()
方法抓取兄弟节点以及TakeWhile()
谓词,以便在适当的时间停止枚举。
首先是辅助方法:
public static Items ItemsFromStartItem(XElement start, XElement group)
{
return new Items
{
GroupNumber = (int)group.Attribute("group"),
ItemNumber = (int)start.Attribute("value"),
ItemText = start.NodesAfterSelf()
.TakeWhile(n => n.NodeType != XmlNodeType.Element
|| ((XElement)n).Name != "endItem")
.OfType<XText>()
.Select(t => t.Value)
.Single()
};
}
public static IEnumerable<Items> ItemsFromBlockOfData(
XElement block, XElement group)
{
return block.Elements("startItem")
.Select(start => ItemsFromStartItem(start, group));
}
神奇的查询。
var query = doc.Descendants("startGroup")
.SelectMany(group => group.ElementsAfterSelf()
.TakeWhile(e => e.Name != "endGroup")
.SelectMany(e => e.Name == "startItem"
? new[] { ItemsFromStartItem(e, group) }
: ItemsFromBlockOfData(e, group))
);
现在我希望你自己不设计这个XML ......这种东西可以真正推动某人超越边缘。 ;)