LINQ to XML递归查询

时间:2011-07-26 20:29:55

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

我有一个像文档树一样构建的xml站点地图,如下所示:

<Site>
<File GUID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx">FileName</file>
<Folder name="FolderName">
    <Security>
        <Role>Admin</role>
    </Security>
    <File GUID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx">FileName</file>
    <Folder name="subFoler">
        <File GUID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx">FileName</file>
        <File GUID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx">FileName</file>
        <Folder>
            <File GUID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx">FileName</file>
        </Folder>
    </Folder>
</Folder>

*请注意,这是我的实际xml文件。实际的xml文件太大而无法显示。基本上你需要消除的是,有可能存在“X”数量的文件夹彼此嵌套,并且在这些文件夹中的某些时候,可能存在“X”个文件以及子文件夹。 / p>

此外,某些文件夹具有安全性,该文件夹由文件夹中的所有继承(文件,子文件夹,子文件夹中的文件等)。我试图提出一个LINQ to XML查询,以获得基于该文件GUID的给定文件的安全性,它适用于level-1和level-2文件,但是当我尝试运行查询时文件是3个文件夹深,它失败,我得到一个nullreference异常。这是我正在使用的查询:

XDocument sitemap = XDocument.Load(HttpContext.Current.Server.MapPath("/.../sitemap.xml"));
        XElement fileFromMap =
            sitemap.Descendants("File").Where(
            file => file.Attribute("GUID").Value == guid).First();

        XElement currentFile = new XElement("File",
            fileFromMap.Value,
            fileFromMap.Ancestors("Folder").SelectMany(
                folder =>
                {
                    XElement security = folder.Element("Security");
                    return (security != null ? security.Elements("Role") : null);
                }));

*并且在信用到期的情况下,我收到了此查询here

null引用异常发生在currentFile变量的声明中,我不知道为什么。我确保Guids匹配......并且因为fileFromMap被正确声明,我知道我的文件正在被找到。我假设这里需要做的是更好地检查父文件夹的安全性。查询可以在找到任何安全性后立即停止,因为站点的设置方式应该没有冲突的安全声明。 (例如,没有已定义安全性的文件夹将位于已定义安全性的文件夹中)

如果我错了,这不是我需要做的,请提供您可能提出的任何建议,并随意更改此问题的标题,以便更好地记录。

1 个答案:

答案 0 :(得分:2)

(如果您在之前的问题中留下评论,那可能是最好的,但我现在也可以回答这个问题,因为它已发布;)

我提供的代码中存在错误:我认为SelectMany()以与null相同的方式折叠了XElement.Add()个项目,而我错了。如果祖先链中有一个没有角色的文件夹,SelectMany()会抛出NullReferenceException

我们只需要提供一个空的XElement枚举来解决问题:

XElement currentFile = new XElement("File",
    fileFromMap.Value,
    fileFromMap.Ancestors("Folder").SelectMany(
        folder =>
        {
            XElement security = folder.Element("Security");
            return (security != null
                    ? security.Elements("Role") : new XElement[0]);
        }));

我会用反向链接更新我的原始答案。