Ключевым моментом здесь является использование методов 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 ... это такие вещи, которые действительно могут кого-то толкнуть за край. ;)