Как вы пишете linq-to-xml для данных между элементами XML? - PullRequest
1 голос
/ 19 февраля 2012

Я пытаюсь проанализировать какой-то 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-потоков и проанализировать его по старинке.

1 Ответ

2 голосов
/ 19 февраля 2012

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...