【问题标题】:How do you write linq-to-xml for data between XML elements?您如何为 XML 元素之间的数据编写 linq-to-xml?
【发布时间】:2012-02-19 09:19:49
【问题描述】:

我正在尝试解析一些与此类似的 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 流阅读器并以老式方式对其进行解析。

【问题讨论】:

  • @Jeff,C# xml 阅读器没有抛出任何错误。我可以使用我的 linq 语句从元素中获取属性。是什么使它无效?也许这就是为什么我不能让它工作。 (我修正了我的错字)。
  • 好吧再看一遍,我想这不是真的无效,只是很不正统。我试着把它读进去,但我得到了一大堆错误。我不知道那里发生了什么,但现在阅读正常。
  • 是的,可以肯定的是非正统。可能是 linq-to-xml 无法处理该数据的格式,但我想我想看看是否有人像以前那样使用 xml 这样做过。
  • 我现在正在写一个答案。这将是一个尴尬但可行的。

标签: c# xml linq linq-to-xml


【解决方案1】:

这里的关键是使用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……这种东西真的可以把某人推到边缘。 ;)

【讨论】:

  • 不,我没有设计那个 XML,但我正在做 ETL 工作。今晚我会试试这个,然后回到这里。非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多