【问题标题】:LINQ to XML query Where() function not returning anythingLINQ to XML 查询 Where() 函数不返回任何内容
【发布时间】:2015-06-08 03:08:34
【问题描述】:

我有一个想要使用 LINQ 解析的 XML 文件,以便获取包含属性 ID 的所有节点。有了这个 ID、节点的名称和它的祖父母的名称,我想在 LINQ 查询中创建一个新对象(EveItem 类型)。

这是我的 XML 文件的一部分,以举例说明它是如何构造的:

<?xml version="1.0" encoding="UTF-8"?>
<Eve_App>
    <Item_Types>
        <Ore>
            <Arkonor_Category>
                <Arkonor ID="22"/>
                <Compressed_Arkonor ID="28367"/>
                <Compressed_Crimson_Arkonor ID="28385"/>
                <Compressed_Prime_Arkonor ID="28387"/>
                <Crimson_Arkonor ID="17425"/>
                <Prime_Arkonor ID="17426"/>
            </Arkonor_Category>

            <Bistot_Category>
                <Bistot ID="1223"/>
                <Compressed_Bistot ID="28388"/>
                <Compressed_Monoclinic_Bistot ID="28389"/>
                <Compressed_Triclinic_Bistot ID="28390"/>
                <Monoclinic_Bistot ID="17429"/>
                <Triclinic_Bistot ID="17428"/>
            </Bistot_Category>

            <Crokite_Category>
                <Compressed_Crokite ID="28391"/>
                <Compressed_Crystalline_Crokite ID="28392"/>
                <Compressed_Sharp_Crokite ID="28393"/>
                <Crokite ID="1225"/>
                <Crystalline_Crokite ID="17433"/>
                <Sharp_Crokite ID="17432"/>
            </Crokite_Category>

            <Dark_Ochre_Category>
                <Compressed_Dark_Ochre ID="28394"/>
                <Compressed_Obsidian_Ochre ID="28395"/>
                <Compressed_Onyx_Ochre ID="28396"/>
                <Dark_Ochre ID="1232"/>
                <Obsidian_Ochre ID="17437"/>
                <Onyx_Ochre ID="17436"/>
            </Dark_Ochre_Category>
            ...
        </Ore>

        <Ice>
            <Ice>
                <Blue_Ice ID="16264"/>
                <CLear_Icicle ID="16262"/>
                <Compressed_Blue_Ice ID="28433"/>
                <Compressed_Clear_Icicle ID="28434"/>
                <Compressed_Dark_Glitter ID="28435"/>
                <Compressed_Enriched_Clear_Icicle ID="28436"/>
                <Compressed_Gelidus ID="28437"/>
                <Compressed_Glacial_Mass ID="28438"/>
                <Compressed_Glare_Crust ID="28439"/>
                <Compressed_Krystallos ID="28440"/>
                <Compressed_Pristine_White_Glaze ID="28441"/>
                <Compressed_Smooth_Glacial_Mass ID="28442"/>
                <Compressed_Thick_Blue_Ice ID="28443"/>
                <Compressed_White_Glaze ID="28444"/>
                <Dark_Glitter ID="16267"/>
                <Enriched_Clear_Icicle ID="17978"/>
                <Gelidus ID="16268"/>
                <Glacial_Mass ID="16263"/>
                <Glare_Crust ID="16266"/>
                <Krystallos ID="16269"/>
                <Pristine_White_Glaze ID="17976"/>
                <Smooth_Glacial_Mass ID="17977"/>
                <Thick_Blue_Ice ID="17975"/>
                <White_Glaze ID="16265"/>
            </Ice>
        </Ice>
        ...

我尝试了以下查询来做我想做的事情,但不幸的是,它不起作用:

items = _xmlFile.Descendants(itemType.ToString())
                    .Where(x => x.Attribute("ID") != null)  // This part returns nothing
                    .Select(x => new EveItem(x.Name.LocalName,
                        (uint)x.Attributes().FirstOrDefault(a => a.Name.LocalName == "ID"), 
                        (EveItem.ItemTypes)itemType)).ToList();

当我在 Visual Studio 中调试此查询时,我可以看到 _xmlFile.Descendants(itemType.ToString()) 返回了我的 XML 文件的好子树,但查询的 .Where(x =&gt; x.Attribute("ID") != null) 部分没有返回任何内容(所以 .Select(..) 没有不会在任何事情上被执行)。我试图通过这个Where(..) 子句得到的是所有实际上在其中声明了ID 属性的节点。

我在这个查询中做错了什么?

编辑:

我尝试从对_xmlFile.Descendants() 的调用中删除itemType.ToString(),它现在可以工作了,尽管我得到了所有具有ID 属性的项目,而不是那些仅在正确的itemType 节点下的项目(矿石、冰等)。

为什么会这样呢?在调试中,我确实看到 _xmlFile.Descendants(itemType.ToString()) 调用返回了正确的 XML 结构。

【问题讨论】:

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


    【解决方案1】:

    那是因为您的物品类型节点(矿石、冰等)都没有ID 属性。该属性在项目类型节点的后代中,因此尝试添加.Descendants()方法调用,如下所示:

    items = _xmlFile.Descendants(itemType.ToString())
                    .Descendants()  //get descendants of current item type
                    .Where(x => x.Attribute("ID") != null)
                    .Select(x => new EveItem(
                                    x.Name.LocalName,
                                    (uint)x.Attributes().FirstOrDefault(a => a.Name.LocalName == "ID"), 
                                    (EveItem.ItemTypes)itemType
                                )
                            )
                    .ToList();
    

    【讨论】:

    • 这行得通。虽然我仍然不明白为什么我必须添加另一个.Descendants().Descendants() 不会发回作为传递给它的节点的子节点的所有元素吗?所以是的,我的 Ore、Ice 等节点没有任何 ID 属性,但它仍然应该检查它们的子节点、孙子节点等,直到叶节点没有?这就是我对函数如何工作的理解,我弄错了吗?
    • 不,你一定很困惑。这里.Descendants(itemType.ToString())descendant_xmlFiledescendant,名字是itemType.ToString())
    • 你确实是对的。我刚刚检查了 msdn 文档并了解了两个函数调用(带参数和不带参数)之间的区别。感谢您指出这一点!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多