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

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

Related

how to print the innertext of an element based on attribute search of a particular node using LINQ?

**I have an XML like this-
<?xml version="1.0" encoding="UTF-8"?>
<Tool_Parent>
<tool name="ABCD" id="226">
<category>Centralized</category>
<extension_id>0</extension_id>
<uses_ids>16824943 16824944</uses_ids>
</tool>
<tool name="EFGH" id="228">
<category>Automated</category>
<extension_id>0</extension_id>
<uses_ids>92440 16824</uses_ids>
</tool>
</Tool_Parent>
Based on the id of tool i want to print the uses_ids value,i.e if i search for 228 i should get 92440 16824.
I had tried like-
var toolData = (from toolElement in doc.Descendants("tool")
select new Tool_poco
{
a_Name = tool.Attribute("name").Value,
a_Id = tool.Attribute("id").Value,
e_ExtensionId = tool.Element("extension_id").Value,
e_UsesIds =tool.Element("uses_parm_ids").Value
});
where Tool_poco is a poco class for tool node containing declaration for member variable.
Now I want to get information related to a particular tool id in toolData variable.How to do it?
Note: I have variable like-
searched_Tool_id = Tool_Id_txtBx.Text.ToString();
Please let me know a way through which i can modify my above query for toolData.**
You can modify your query as
Tool_poco toolData = (from el in xelement.Elements("Employee")
where (string)el.Attribute("id") == "226"
select new Tool_poco
{
a_Name = el.Attribute("name").Value,
a_Id = el.Attribute("id").Value,
e_ExtensionId = el.Element("Name").Value,
e_UsesIds = el.Element("uses_ids").Value
}).FirstOrDefault();
You could start by doing something like this once you have an XDocument object loaded and ready:
var xdoc = XDocument.Parse(
#"<?xml version=""1.0"" encoding=""utf-8""?>
<Tool_Parent>
<tool name=""ABCD"" id=""226"">
<category>Centralized</category>
<extension_id>0</extension_id>
<uses_ids>16824943 16824944</uses_ids>
</tool>
<tool name=""EFGH"" id=""228"">
<category>Automated</category>
<extension_id>0</extension_id>
<uses_ids>92440 16824</uses_ids>
</tool>
</Tool_Parent>");
var root = xdoc.Root; // Got to have that root
if (root != null)
{
var id228query = (from toolElement in root.Elements("tool")
where toolElement.HasAttributes
where toolElement.Attribute("id").Value.Equals("228")
let xElement = toolElement.Element("uses_ids")
where xElement != null
select xElement.Value).FirstOrDefault();
Console.WriteLine(id228query);
Console.Read();
}
Output: 92440 16824
**Note: In reference to your example, one possible reason it was not working
for you could be that your xml references an element with name "uses_ids",
however, your query references an element with a similar, but not exact,
spelling with name "uses_parm_ids".**

Trying to delete an XML Node based on attribute value

I am trying to delete one record from the XML based on some attribute value. My XML structure is given below:
<?xml version="1.0" encoding="utf-8"?>
<Users>
<User>
<UserId>12345</UserId>
<FirstName>abcd</FirstName>
<LastName>efgh</LastName>
<Email>Hello#hello.com</Email>
<IsAdmin>No</IsAdmin>
</User>
<User>
<UserId>67890</UserId>
<FirstName>ijklm</FirstName>
<LastName>nopqr</LastName>
<Email>world#world.com</Email>
<IsAdmin>No</IsAdmin>
</User>
<User>
<UserId>12678</UserId>
<FirstName>stuv</FirstName>
<LastName>wxyz</LastName>
<Email>foo#bar.com</Email>
<IsAdmin>Yes</IsAdmin>
</User>
</Users>
E.g if attribute value is 12345 it should delete the below record from the XML.
<User>
<UserId>12345</UserId>
<FirstName>abcd</FirstName>
<LastName>efgh</LastName>
<Email>Hello#hello.com</Email>
<IsAdmin>No</IsAdmin>
</User>
I tried below code but I am not able to delete anything from the XML.
string path = Server.MapPath("~/XML/users.xml");
XElement xEle = XElement.Load(path);
var qry = from element in xEle.Descendants()
where (string)element.Attribute("UserId").Value == "12345"
select element;
if (qry.Count() > 0)
qry.First().Remove();
xEle.Save(path);
I am unable to figure this out. Any help with be appreciated. Thank you
<UserId>12345</UserId> is a nested sub-element of <User>, not an attribute. See XML attribute vs XML element to see the difference.
Thus you need to do:
var userId = "12345";
var qry = from element in xEle.Descendants("User")
where (string)element.Element("UserId") == userId
select element;
var first = qry.FirstOrDefault();
if (first != null)
first.Remove();
Incidentally, by calling both Count() and First(), you are evaluating your query twice. FirstOrDefault() returns the first matching element, or null if the enumerable is empty, and is thus more efficient.
UserId is not attribute in the XML. Its an element
XElement xEle = XElement.Load("input.xml");
var qry = from element in xEle.Descendants()
where (string)element.Element("UserId") == "12345"
select element;
if (qry.Count() > 0)
qry.First().Remove();
xEle.Save("input.xml");
And in your snippet you are comparing 12345 int with string type

Getting specific data in node by other data in same node

I got XML like that:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!--Some comment-->
<Databook>
<Note>
<Name>Camera2 made a snapshoot #243</Name>
<Value>Camera2_snapshoot-2013-09-06_21-47-35.png</Value>
</Note>
<Note>
<Name>Camera1 made a snapshoot #244</Name>
<Value>Camera1_snapshoot-2013-09-06_21-47-39.png</Value>
</Note>
</Databook>
And i want to get string beetwen [Value]..[/Value] of specific node, knowing only it's string of [Name]..[/Name].
This what i did so far:
string xmlfile = string.Format("XML/Diary/" + day);
XDocument dailyXML = XDocument.Load(xmlfile);
XElement Contact = (from xml2 in dailyXML.Descendants("Note")
where xml2.Element("Name").Value == item
select xml2).FirstOrDefault();
You are very close, if you just want the value of Value where the Name equals item
Try:
string result = (from xml2 in dailyXML.Descendants("Note")
where xml2.Element("Name").Value == item
select xml2.Element("Value").Value).FirstOrDefault();
or
string result = dailyXML.Descendants("Note")
.Where(n => n.Element("Name").Value == item)
.FirstOrDefault(n => n.Element("Value").Value);

Finding a specific xml element containt

Ihave a large xml file and I want to get child element value by giving the parent child element value, I am new in xml file please any help here is my xml:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<masterController> <uuid>XXXXXXXXXXXXXXXXXXXXXXXXX</uuid>
<channels>
<channel>
<nodeGroups>
<nodeGroup>
<analogNode>
<typeCode>8</typeCode>
<id>1</id>
<sdos>
<sdo>
<description>Host ID</description>
<compareLevel>Ignore</compareLevel>
<datafield xmlns:xsi="http://www.XXXXX.XXXX/XXXXX/XMLSchema-instance"
xsi:type="intField">
<description>Host ID</description>
<compareLevel>Ignore</compareLevel>
<offset>2</offset>
<size>1</size>
<readonly>true</readonly>
<isMappedToPdo>false</isMappedToPdo>
<ownerNodeSerial>12102904</ownerNodeSerial>
<ownerSdoIndex>3</ownerSdoIndex>
<data xsi:type="intData">
<value xmlns:xs="http://www.XX.CC/2XXX/XMLSchema" xsi:type="xs:int">2</value>
<unit></unit>
<min>1</min>
<max>15</max>
</data>
<intValue>2</intValue>
</datafield>
<index>3</index>
<totalbytes>3</totalbytes>
</sdo>
<sdo>
<description>Host ID</description>
<compareLevel>Ignore</compareLevel>
<datafield xmlns:xsi="http://www.XXXXX.XXXX/XXXXX/XMLSchema-instance"
xsi:type="intField">
<description>Host ID</description>
<compareLevel>Ignore</compareLevel>
<offset>2</offset>
<size>1</size>
<readonly>true</readonly>
<isMappedToPdo>false</isMappedToPdo>
<ownerNodeSerial>12102905</ownerNodeSerial>
<ownerSdoIndex>4</ownerSdoIndex>
<data xsi:type="intData">
<value xmlns:xs="http://www.XX.CC/2XXX/XMLSchema" xsi:type="xs:int">16</value>
<unit></unit>
<min>1</min>
<max>15</max>
</data>
<intValue>2</intValue>
</datafield>
<index>3</index>
<totalbytes>3</totalbytes>
</sdo>
</sdos>
</analogNode>
</nodeGroup>
</nodeGroups>
</channel> </channels> </masterController>
I' am trying this but am not geting anything:
XElement root = XElement.Load(Server.MapPath("sample.xml"));
IEnumerable<XElement> masterco = from el in root.Elements("sdo") where (from add in el.Elements("datafield")
where
(string)add.Element("ownerNodeSerial") == TextBox1.Text &&
(string)add.Element("ownerSdoIndex") == TextBox1.Text
select add)
.Any()
select el;
foreach (XElement el in masterco)
{
TextBox3.Text = (string)el.Element("value");
}
I want to get this:
<value xmlns:xs="http://www.XX.CC/2XXX/XMLSchema" xsi:type="xs:int">16</value>
and be able to update it.
There is one major error in your query:
You are using Elements on root, but you are looking for the tag sdo which is not a direct child of the root tag. You have to use Descendants instead.
Additionally, I think you want to have an OR instead of an AND regarding the text of TextBox1.
Fix it:
var masterco = from el in root.Descendants("sdo")
where (from add in el.Elements("datafield")
where
(string)add.Element("ownerNodeSerial") == TextBox1.Text ||
(string)add.Element("ownerSdoIndex") == TextBox1.Text
select add).Any()
select el;
To actually get the value you want, you should use a different query. There is really no need to select the sdo tag at all.
var value = root.Descendants("datafield")
.Where(x => (string)x.Element("ownerNodeSerial") == TextBox1.Text ||
(string)x.Element("ownerSdoIndex") == TextBox1.Text)
.Select(x => (string)x.Element("data").Element("value"))
.Single();
TextBox3.Text = value;
You can see that I am assuming that in the whole XML document only one matching datafield/data/value entry exists. I derive that information from the way you update your textbox. This would make no sense if there would be multiple tags - the values would overwrite each other in the text box.

I'm confused by Linq XML query

Here is my XML sample. I want to select SystemSetting's value if ID = 123. But I can't figure out how. How can I select SystemSetting value if id's value equal to 123 ?
<?xml version="1.0" encoding="utf-8" ?>
<Private>
<System>
<ID>123</ID>
<NAME>Test</NAME>
<SystemSetting>128</SystemSetting>
<SystemSettingCS>127</SystemSettingCS>
</System>
<System>
<ID>124</ID>
<NAME>Test2</NAME>
<SystemSetting>128</SystemSetting>
<SystemSettingCS>127</SystemSettingCS>
</System>
<System>
<ID>0</ID>
<NAME>Test</NAME>
<SystemSetting>5</SystemSetting>
<SystemSettingCS>250</SystemSettingCS>
</System>
</Private>
Here's what I tried:
var doc = XDocument.Load(Application.StartupPath+ #"\Settings.xml");
var q = from Ana in doc.Descendants("Private")
from sistem in Ana.Elements("System")
where (int)sistem.Element("ID") == 123
from assetText in Sistem.Elements("System")
select assetText.Element("SystemSetting");
MessageBox.Show(q.ToString());
thnx for help.
I think you're making this more complicated than you need to. I think you just need:
var query = doc.Descendants("Private") // Or just doc.Root
.Elements("System")
.Where(x => (int) x.Element("ID") == 123)
.Select(x => x.Element("SystemSetting"))
.FirstOrDefault();
That will select the first matching element, admittedly. The type of query is then XElement; if you take off the FirstOrDefault() part, it will return an IEnumerable<XElement>, for all matching elements.
If you want just the value instead of the element, you can change the Select to:
.Select(x => (string) x.Element("SystemSetting"))
or
.Select(x => x.Element("SystemSetting").Value)
(The first will return null if there's no SystemSetting element; the second will throw an exception.)
Xpath (System.Xml.XPath) can really help here
var system = doc.XPathSelectElement("//System[ID[text()='123']]");
var val = system.Element("SystemSetting").Value;
or with a single line
var s = (string)doc.XPathSelectElement("//System[ID[text()='123']]/SystemSetting");
Your almost there
var xmlFile = XElement.Load(#"c:\\test.xml");
var query =
from e in xmlFile.Elements()
where e.Element("ID").Value == "123"
select e.Element("SystemSetting").Value;
var q = from s in doc.Descendants("System")
where (int)s.Element("ID") == 123
select (int)s.Element("SystemSetting");
And show result (q will have IEnumerable<int> type):
if (q.Any())
MessageBox.Show("SystemSettings = " + q.First());
else
MessageBox.Show("System not found");
Was a Linq question, but there is an alternate XPath approach, but the class defined below could work in either scenario.
Define a class to read from the parent System element:
public class XSystem
{
public XSystem(XElement xSystem) { self = xSystem; }
XElement self;
public int Id { get { return (int)self.Element("ID"); } }
public string Name { get { return self.Element("NAME").Value; } }
public int SystemSetting { get { return (int)self.Element("SystemSetting"); } }
public int SystemSettingCS { get { return (int)self.Element("SystemSettingCS"); } }
}
Then find your System element that has a child ID element of 123.
int id = 123;
string xpath = string.Format("//System[ID={0}", id);
XElement x = doc.XPathSelectElement(xpath);
Then plug it into the class:
XSystem system = new XSystem(x);
Then read the value you want:
int systemSetting = system.SystemSetting;
XPath is defined with using System.Xml.XPath;

Categories

Resources