LINQ Search attributes on different levels - c#

I would like to search xml file with LINQ technology but have some difficulties.
I would like to find all childs with attribute value and some search condition
My XML (structured data) looks like this:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<LanguageMenu>
<Menu language="English" name ="Menu" numOfMenus="1">
<MainItem ID="e_mnuMain1" name="File" level="0"></MainItem>
<MainItem ID="e_mnuMain2" name="Edit" level="0"></MainItem>
<MainItem ID="e_mnuMain3" name="Query" level="0"></MainItem>
<MainItem ID="e_mnuMain4" name="Traffic" numOfSubItem="4" level="0">
<SECOND name="Vendors" value="FIN3010" level="1" father="3"></SECOND>
<SECOND name="Buyers" value="FIN3020" level="1" father="3" ></SECOND>
<SECOND name="General ledger" value="FIN3030" level="1" father="3"></SECOND>
<SECOND name="Accounts" value="FIN3040" level="1" father="3">
<THIRD name="Home Accounts" value="FIN3010" level="2" father="5" grantfather="3"/>
<THIRD name="Foreign accounts" value="FIN3050" level="2" father="5" grantfather="3"/>
</SECOND>
</MainItem>
</Menu>
</LanguageMenu>
With LINQ I would like to achieve to find all childrens beginning with Element MainItem that have value FIN3010.
Based on my XML it should return Vendors and Home Accounts.
I would also like to get the parents of that childer so the output I would like to achieve will be like this:
Traffic - Vendors
Traffic - Accounts - Home Accounts
I have stucked with this piece of code:
XElement xelement = XElement.Load("../../xmlFile");
var x = from a in xelement.Descendants("SECONDS")
where a.Attribute("value") != null
&& (string)a.Attribute("value").Value.ToUpper() == txtSifra.Text.ToUpper()
select a;
foreach (XElement xEle in x)
{
//TODO
}

How about this:
var x = from a in xelement.Descendants("MainItem")
.Descendants()
where a.Attribute("value") != null &&
a.Attribute("value").Value
.Equals(txtSifra.Text,
StringComparison.InvariantCultureIgnoreCase)
select a;
foreach (XElement xEle in x)
{
// items will contain all nodes (inclusive) between MainItem and xEle
var items = xEle.AncestorsAndSelf()
.Where(x1 => x1.AncestorsAndSelf("MainItem")
.Any())
.OrderBy(x1 => x1.Ancestors().Count());
var names = items.Attributes("name").Select(a => a.Value).ToArray();
Console.WriteLine(string.Join(" - ", names));
}
The output from this is:
Traffic - Vendors
Traffic - Accounts - Home Accounts

Related

Linq to XML delete parent node

I'm trying to delete a parent from a element in XML.
My XML:
<root>
<Element1 ManagementID="10" />
<Users>
<UserID ManagementID="10">
<Identification IDValue="1" />
<!-- More elements Here -->
</UserID>
</Users>
<!-- More Users elements Here -->
I find my user my its IDValue:
XElement user = (from el in document.Root.Elements("Users").Elements("UserID ").Elements("Identification")
where (string)el.Attribute("IDValue") == myID
select el).FirstOrDefault();
Now, I would like to remove all the user.Parent.Parent
I mean delete the element:
<Users>
<UserID ManagementID="10">
<Identification IDValue="1" />
<!-- More elements Here -->
</UserID>
</Users>
** I'll have many Users elements, that's why first I look for the identification IDValue
I found the solution for who needs it:
I already had the node from my linq so
user.Parent.Parent.Remove()
var user = document.Root
.XPathSelectElements("//UserId")
.FirstOrDefault(userId => userId.Element("Identification").Attribute(XName.Get("IDValue")).Value == myID);
Try this :
List<XElement> users = document.Descendants("Users")
.Where(user => user.Elements("Identification")
.Where(el => (string)el.Attribute("IDValue") != myID)
.Any()).ToList();
XElement element1 = document.Descendants("Element1").FirstOrDefault();
element1.ReplaceNodes(users);

Not able to select relevant nested nodes: LINQ

My sample XML is something like this:
<?xml version="1.0" encoding="utf-8"?>
<Root>
<RoleSecurity Name="A" Workflowstatus ="B">
<Accountgroup Name = "Group1">
<Attribute ID="12345" Name="Sample1"/>
<Attribute ID="12445" Name="Sample2"/>
</Accountgroup>
<Accountgroup Name = "Group2">
<Attribute ID="12345" Name="Sample1"/>
<Attribute ID="12445" Name="Sample2"/>
</Accountgroup>
</RoleSecurity>
</Root>
I am trying to enumerate and extract all the ID corresponding to a particular Role name, workflow status and account group.
My LINQ query is working to select a node based on role name. But I am unable to proceed further.
Please help!
This is my LINQ code till now.
XElement xcd = XElement.Load(strFileName);
IEnumerable<XElement> enumCust = from cust in xcd.Elements("RoleSecurity")
where (string)cust.Attribute("Name") == strRole
select cust;
Try this:
string roleName = "A";
string workflowStatus = "B";
string accountGroup = "Group1";
string xml = #"<?xml version=""1.0"" encoding=""utf-8""?>
<Root>
<RoleSecurity Name=""A"" Workflowstatus =""B"">
<Accountgroup Name = ""Group1"">
<Attribute ID=""12345"" Name=""Sample1""/>
<Attribute ID=""12445"" Name=""Sample2""/>
</Accountgroup>
<Accountgroup Name = ""Group2"">
<Attribute ID=""12345"" Name=""Sample1""/>
<Attribute ID=""12445"" Name=""Sample2""/>
</Accountgroup>
</RoleSecurity>
</Root>";
XElement element = XElement.Parse(xml);
var ids = element.Elements("RoleSecurity")
.Where(
e =>
(string) e.Attribute("Name") == roleName &&
(string) e.Attribute("Workflowstatus") == workflowStatus)
.Elements("Accountgroup").Where(e => (string) e.Attribute("Name") == accountGroup)
.Elements("Attribute")
.Select(e => new {ID = (string) e.Attribute("ID"), Name = (string) e.Attribute("Name")});
Try with this approach, seems different from your (and in some aspects it really changes), but in my opinion its a good way to use fluently a LINQ query to parse an XML file, it follows XML node sequence and it's easy to understand:
XElement element = XElement.Load(strFileName);
var linqList = element.Elements("RoleSecurity")
.Where(entry => entry.Attribute("Name").Value == "A" &&
entry.Attribute("Workflowstatus").Value == "B")
.Descendants("Accountgroup")
.Where(x => x.Attribute("Name").Value == "Group1")
.Descendants("Attribute")
.SelectMany(id => id.Attribute("ID").Value);
XElement xcd = XElement.Load(strFileName);
IEnumerable<XElement> enumCust = from cust in xcd.Root.Elements("RoleSecurity")
where cust.Attribute("Name").Value == strRole
select cust;
This should work now
you were missing .Root which is required to enumerate below the root node
and .Value to retrive the string value of the specified attribute
refer this artical :- http://www.dotnetcurry.com/ShowArticle.aspx?ID=564
foreach (XElement xcd xelement.Descendants("Id"))
{
Console.WriteLine((string)xcd);
}

Basic filtering in LINQ to XML Queries

I am new to XDocument and LINQ. Here is what I am trying to do :
XML file :
<?xml version="1.0" encoding="utf-8"?>
<root>
<chapters total-chapters="3">
<Chapter chapter-no="1">
<chapter-summary>this is chapter 1</chapter-summary>
</Chapter>
<Chapter chapter-no="2">
<chapter-summary>this is chapter 2</chapter-summary>
</Chapter>
<Chapter chapter-no="3">
<chapter-summary>this is chapter 3</chapter-summary>
</Chapter>
<Chapter chapter-no="4">
<chapter-summary>this is chapter 4</chapter-summary>
</Chapter>
</chapters>
</root>
Now I need to read all the records with a specific chapter-no. I am writing my LINQ query as :
IEnumerable<XElement> elem_list =
from e in xdoc.Elements("Chapter")
where (string) e.Attribute("chapter-no") == "1"
select e;
foreach (XElement e in elem_list)
{
Console.WriteLine(e);
}
but elem_list is not getting populated and nothing is displayed.
.Elements("Chapter") search only within direct children of current element (root for xdoc).
You can use .Descendants("Chapter"):
IEnumerable<XElement> elem_list = from e in xdoc.Descendants("Chapter")
where (string) e.Attribute("chapter-no") == "1"
select e;
Or specify full item path:
IEnumerable<XElement> elem_list = from e in xdoc.Root.Element("chapters").Elements("Chapter")
where (string) e.Attribute("chapter-no") == "1"
select e;
Another approach - with XPath selector:
xdoc.XPathSelectElements("root/chapters/Chapter[#chapter-no=1]");
using System.Xml.XPath; is necessary to make the last sample work.
You can do something like the following:
IEnumerable<XElement> elem_list =
xdoc.Descendants("Chapter")
.Where (c => c.Attribute("chapter-no").Value.Equals("1"));

C# Linq XML, check for specific value and parse to array

I have the following XML:
<?xml version="1.0" ?>
<NewDataSet>
<Data>
<ElementDefinition>
<ID>1</ID>
<QUANTITY>0</QUANTITY>
</ElementDefinition>
<ElementDefinition>
<ID>2</ID>
<QUANTITY>1</QUANTITY>
</ElementDefinition>
</Data>
</NewDataSet>
I need to create an array which contains all ElementDefinitions which contain a QUANTITY element with a value other then 0.
I tried:
var f = XDocument.Load(path);
var xe = f.Root.Elements("QUANTITY").Where(x => x.Value != "0").ToArray();
But that doesn't seem to work. With the above XML the array should contain 1 item, but it stays 0.
After that I need to create a string for each ElementDefinition in the array, the string must contain the value of the corresponding ID element.
For that I tried:
foreach (string x in xe)
{
string ID = //not sure what to do here
}
You want something like this:
var ids = f.Root.Descendants("ElementDefinition")
.Where(x => x.Element("QUANTITY").Value != "0")
.Select(x => x.Element("ID").Value);
As you want the ID, it is not very helpful to select all QUANTITY nodes. Instead, select exactly what you specified in your question:
All ElementDefinitions (Descendants("ElementDefinition")), that have a QUANTITY with a Value other than 0 (Where(x => x.Element("QUANTITY").Value != "0"). From the resulting nodes, select the ID (Select(x => x.Element("ID").Value)).
Yo can replace with
var xe = f.Root.Elements("Data/ElementDefinition/QUANTITY").Where(x => x.Value != "0").ToArray();

Search XML doc with LINQ

I have an xml doc similar to this:
<Root>
<MainItem ID="1">
<SubItem></SubItem>
<SubItem></SubItem>
<SubItem></SubItem>
</MainItem>
<MainItem ID="2">
<SubItem></SubItem>
<SubItem></SubItem>
<SubItem></SubItem>
</MainItem>
...
</Root>
I want to return the whole of the MainItem element based on the value of attribute ID.
So effectively if Attribute ID is equal to 2, then give me that MainItem element back.
I can't work out how to do this with LINQ.
There seems to be a load of information on google, but I just can't quite seem to find what I'm looking for.
Little help ?
TIA
:-)
It could be something like this:
XDocument doc = XDocument.Load("myxmlfile.xml");
XElement mainElement = doc.Element("Root")
.Elements("MainItem")
.First(e => (int)e.Attribute("ID") == 2);
// additional work
How about this:
// load your XML
XDocument doc = XDocument.Load(#"D:\linq.xml");
// find element which has a ID=2 value
XElement mainItem = doc.Descendants("MainItem")
.Where(mi => mi.Attribute("ID").Value == "2")
.FirstOrDefault();
if(mainItem != null)
{
// do whatever you need to do
}
Marc
I changed your XML slightly to have values:
<?xml version="1.0"?>
<Root>
<MainItem ID="1">
<SubItem>value 1</SubItem>
<SubItem>val 2</SubItem>
<SubItem></SubItem>
</MainItem>
<MainItem ID="2">
<SubItem></SubItem>
<SubItem></SubItem>
<SubItem></SubItem>
</MainItem>
</Root>
And with this LINQ:
XDocument xmlDoc = XDocument.Load(#"C:\test.xml");
var result = from mainitem in xmlDoc.Descendants("MainItem")
where mainitem.Attribute("ID").Value == "1"
select mainitem;
foreach (var subitem in result.First().Descendants())
{
Console.WriteLine(subitem.Value);
}
Console.Read();
From here: How to: Filter on an Attribute (XPath-LINQ to XML)
// LINQ to XML query
IEnumerable<XElement> list1 =
from el in items.Descendants("MainItem")
where (string)el.Attribute("ID") == "2"
select el;
// XPath expression
IEnumerable<XElement> list2 = items.XPathSelectElements(".//MainItem[#ID='2']");

Categories

Resources