2

I have the following xml file:

<Object type="User">
    <Attribute name="Name">usernameExample</Attribute>
    <Attribute name="Title">FHen</Attribute>
    <Attribute name="AdministratedBy">Admin</Attribute>
    <Attribute name="Password">123</Attribute>
    <Attribute name="TimeOut">00:20:00</Attribute>
    <Object type="AreasFolder">
        <Attribute name="Name">Areas</Attribute>
        <Attribute name="Comment">This folder contains ...</Attribute>
        <Object type="Area">
            <Attribute name="Name">RootArea</Attribute>
            <Attribute name="AccessLevel">None</Attribute>
        </Object>
        <Object type="Area">
            <Attribute name="Name">FRF</Attribute>
            <Attribute name="AccessLevel">Admin</Attribute>
        </Object>
    </Object>
</Object>

and my goal is to get the name of the Areas which have AccessLevel != None by the user name. I already can get the Areas inside the user and I can filter them using c# logic but I would like to do that with a Linq Xml query.

Right now I've done the following:

In my main:

logic.tryXdoc("usernameExample");

In my Logic.cs:

public void tryXdoc(string username)
    {
        List<string> lista = new List<string>();

        XElement ConfigData = XElement.Load(UsersXmlPath);

        XElement scadaUsers =
            (from xElement in ConfigData.Elements("Object")
                 //where (string)xElement.Element("type") == "User"
             select xElement).First();

        XElement usersFolder =
            (from xElement in scadaUsers.Elements("Object")
             where (string)xElement.Attribute("type") == "UsersFolder"
             select xElement).First();

        IEnumerable<XElement> users =
             from xElement in usersFolder.Elements("Object")
             where (string)xElement.Attribute("type") == "User"
             select xElement;

        XElement user =
             (from xElement in users
              where (string)xElement.Element("Attribute").Attribute("name") == "Name"
              && (string)xElement.Element("Attribute") == username
              select xElement).First();

        XElement areasFolder =
             (from xElement in user.Elements("Object")
              where (string)xElement.Attribute("type") == "AreasFolder"
              select xElement).First();

        IEnumerable<XElement> areas =
             from xElement in areasFolder.Elements("Object")
             where (string)xElement.Attribute("type") == "Area"
             select xElement;        
    }

Now, I would like something like this:

        IEnumerable<XElement> visibleAreas =
             from xElement in areas.Elements("Attribute")
             where 
             (string)xElement.Attribute("name") == "AccessLevel"
             && (string)xElement.Attribute("name").Value != "None"
             select xElement;

And I would like to get only one Area, because there is just one with AccessLevel != "None" but I get the same result as areas. I don't know how to tell my program that the xElement.Attribute("name").Value that I want it to compare to "None" it the Value of the xElement.Attribute("name") that I compared with AccessLevel.

I have already tried to use Descendants().Where( something ) but I get the same. I tried to use Descendants().Where(something.Where( something else )) but I can't compile.

I can get the areas that I want using:

        List<List<XElement>> listAreaAttributes = new List<List<XElement>>();

        foreach (XElement xElement in areas)
        {
            List<XElement> areaAttributes = new List<XElement>();

            foreach (XElement xEl in xElement.Elements("Attribute"))
            {
                areaAttributes.Add(xEl);
            }

            listAreaAttributes.Add(areaAttributes);
        }

and then comparing the areaAttributes but I know it is possible to make this with a query so I don't want to use processment making this.

2
  • It's definitely possible to write a LINQ query for this. Can you please clarify what value(s) visibleAreas you expect to have? Is it the whole <Object type="Area"> element? Or just an <Attribute name="Name">FRF</Attribute> element? Or something else? Commented Aug 31, 2016 at 19:15
  • I want to get FRF, in this case. But if it is easier, I could get the whole Area object and then I take the name out of there. In the case of the User it just worked because the name is the first attribute but the query is not really well done Commented Sep 1, 2016 at 8:33

1 Answer 1

1

How about modifying this to fit your user, if you want to do it on a per-user bases. This assumes that the order of your XML is exact, and that the AccessLevel Name is always the node immediately previous to the AccessLevel.

List<string> visibleAreas = ConfigData.Descendants("Attribute")
    .Where(x => x.Attribute("name").Value == "AccessLevel")
    .Where(x => x.Value != "None")
    .Select(x => ((XElement)x.PreviousNode).Value)
    .ToList();
Sign up to request clarification or add additional context in comments.

1 Comment

I get 213 results with that query because my xml file is big and there are a lot of users with a lot of areas. I just put a part of the xml in my question. But if I substitute ConfigData for user, it solves my problem. Thank you very much!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.