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.
答案 0 :(得分: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();