LINQ to XML recursive query

安稳与你 提交于 2020-01-23 12:07:51

问题


I have an xml sitemap structured like a document tree, such that it looks like this:

<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>

*Note that this is NOT my actually xml file. The actual xml file is too big to just show. Basically what you need to take away from this is that there are potentially 'X' amount of folders nested within each other, and at some point in those folders, there can be 'X' amount of files, as well as children folders.

Also, some folders are given security, which is inherited by everything in that folder (files, child folders, files within child folders, etc). I am trying to come up with a LINQ to XML query to get the security of a given file based on that files GUID, and it works fine for level-1 and level-2 files, but when I try to run the query on a file that is 3 folders deep, it fails and I get a nullreference exception. Here is the query I am using:

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);
                }));

*and credit where credit is due, I got this query here

The nullreference exception is happening in the declaration of the currentFile variable, and I'm not sure why. I've made sure that the Guids match up...and since fileFromMap is being declared correctly, I know that my file is being found. I assume what needs to be done here is something to better check parent folders recursively for security. The query can stop as soon as it finds any security, because the way the site is set up, there should be no conflicting security declarations. (eg, no folder that has defined security will be within a folder that already has defined security)

If I am wrong, and this isn't what I need to do, please offer any suggestions you may have, and feel free to change the title of this question accordingly as to better document it.


回答1:


(It would probably have been best if you left me a comment in your previous question instead, but I might as well answer this one now that it's posted ;)

There's a mistake in the code I provided: I thought SelectMany() collapsed null items in the same way XElement.Add() does, and I was wrong. If there is a folder without roles in the ancestor chain, SelectMany() will throw a NullReferenceException.

We only need to feed it an empty enumerable of XElement to solve the problem:

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]);
        }));

I'll update my original answer with a backlink.



来源:https://stackoverflow.com/questions/6836187/linq-to-xml-recursive-query

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!