XElement.Elements() returning empty collection - c#

I'm trying to get the values from an XElement that I'm receiving from db notification.
The xml structure is like this:
<?xml version="1.0"?>
<root>
<inserted>
<row>
<CODI_AVERIA>22</CODI_AVERIA>
<NUMERO_LINIA>2</NUMERO_LINIA>
<DIA>2016-07-17T00:00:00</DIA>
<HORA>1899-12-30T10:26:15.790</HORA>
<CODI_USUARI>1</CODI_USUARI>
<ACCIO>0</ACCIO>
<CODI_PSEUDO>-1</CODI_PSEUDO>
</row>
</inserted>
</root>
And this is the method that I'm using to get the data, and it returns me a List that is empty.
static void getAccio(XElement xml)
{
try
{
xml.Descendants("deleted").Remove();
var items = xml.Elements("row").Select(n => new
{
Codi_averia = n.Element("CODI_AVERIA").Value,
Numero_linia = n.Element("NUMERO_LINIA)").Value,
Accio = n.Element("ACCIO").Value
}).ToList();
}
catch (Exception e)
{
Console.Write(e.Message);
}
}
I have tried to get the value of each field apart and it doesn't allow me to get them separetly as XElements.

Use .Descendants() instead of .Elements():
var items = xml.Descendants("row").Select(n => new
{
Codi_averia = n.Element("CODI_AVERIA").Value,
Numero_linia = n.Element("NUMERO_LINIA)").Value,
Accio = n.Element("ACCIO").Value
}).ToList();
.Elements finds only those elements that are direct descendents, i.e. immediate children. - And I assume that your XElement is the parent of the inserted section.
For difference between .Element and .Descendants see this question
If you don't want to find them in all inner elements too then do .Element("inserted").Elements("rows")

Your document doesn't have any root element with the name row. Instead, you need to select inserted first, and enumerate the row elements of inserted:
var xml = #"<inserted>
<row>
<CODI_AVERIA>21</CODI_AVERIA>
<NUMERO_LINIA>2</NUMERO_LINIA>
<DIA>2016-07-17T00:00:00</DIA>
<HORA>1899-12-30T10:26:15.790</HORA>
<CODI_USUARI>1</CODI_USUARI>
<ACCIO>0</ACCIO>
<CODI_PSEUDO>-1</CODI_PSEUDO>
</row>
</inserted>";
var xdoc = XDocument.Parse(xml);
var items = xdoc.Element("inserted").Elements("row").Select(n => new
{
Codi_averia = n.Element("CODI_AVERIA").Value,
Numero_linia = n.Element("NUMERO_LINIA").Value,
Accio = n.Element("ACCIO").Value
}).ToList();

In your sample code ("NUMERO_LINIA)") is wrong because of additionnal quote and parenthesis.
This works for me :
XDocument xd = XDocument.Load("XMLFile1.xml");
var lst = (from n in xd.Descendants("row")
select new
{
Codi_averia = n.Element("CODI_AVERIA").Value,
Numero_linia = n.Element("NUMERO_LINIA").Value,
Accio = n.Element("ACCIO").Value
}).ToList();
foreach (var item in lst)
Console.WriteLine(string.Format("{0}{1}{2}", item.Codi_averia, item.Numero_linia, item.Accio));

Related

Xml file with C# can't get the value

Here is my xml file
<?xml version="1.0" encoding="ASCII"?>
<Vitals>
<Vendor>General Electric Healthcare</Vendor>
<Model>Pro/Procare</Model>
<Result name="Mean_arterial_pressure">
<Value>86</Value>
<Units name="mmHg"></Units>
<Time_stamp year="2008" month="11" day="18" hour="12" minute="33" second="14"></Time_stamp>
</Result>
<Result name="Systolic_blood_pressure">
<Value>130</Value>
<Units name="mmHg"></Units>
<Time_stamp year="2008" month="11" day="18" hour="12" minute="33" second="14"></Time_stamp>
</Result>
<Result name="Diastolic_blood_pressure">
<Value>67</Value>
<Units name="mmHg"></Units>
<Time_stamp year="2008" month="11" day="18" hour="12" minute="33" second="14"></Time_stamp>
</Result>
<Result name="Pulse">
<Value>73</Value>
<Units name="BPM"></Units>
<Method>blood_pressure</Method>
<Time_stamp year="2008" month="11" day="18" hour="12" minute="33" second="14"></Time_stamp>
</Result>
</Vitals>
and Here is my sourcecode, I having the issue how to get the result name and the value?
private void btnReadXml_Click(object sender, EventArgs e)
{
Hashtable h = new Hashtable();
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("C:\\dinamap.xml");
XmlNodeList doc_results = xmlDoc.GetElementsByTagName("Vitals/Vendor/Model/Result[#name='Systolic_blood_pressure']");
foreach (XmlNode pnode in doc_results)
{
foreach (XmlNode cnode in pnode.ChildNodes)
{
if (cnode.Name == "Value")
{
h.Add(pnode.Attributes["name"].InnerText + cnode.Name, cnode.Attributes["name"].InnerText);
}
else
{
h.Add(pnode.Attributes["name"].InnerText + "_" + cnode.Name, cnode.InnerText);
}
}
}
}
May I know what wrong of my code? always can't get the value.
I need to get the value from xml file.
On line 5, your xPath specify Model is a child of Vendor while Vendor contains only a string (<Vendor>General Electric Healthcare</Vendor>).
Moreover, to navigate with xPath i advice you to use SelectNodes function.
Try this instead :
XmlNodeList doc_results = xmlDoc.SelectNodes("/Vitals/Model/Result[#name='Systolic_blood_pressure']");
It'd be easier if you used LINQ to XML for this.
var doc = XDocument.Load("path/to/xml");
var results =
from result in doc.Descendants("Result")
select new
{
Name = (string) result.Attribute("name"),
Value = (string) result.Element("Value"),
Units = (string) result.Element("Units").Attribute("name")
};
You could then filter by Name if you needed:
var sysBp = results.Single(x => x.Name == "Systolic_blood_pressure");
See this fiddle for a working demo.
You're currently trying to retrieve the "name" attribute of the child node, which it does not actually have in the case of your value node. If you use cnode.Value you can get the contents of a text note.
Also, Result is not a child of Model, which is not a child of Vendor. You'll either want to properly make them children or change the path you're setting for doc_results
private void btnReadXml_Click(object sender, EventArgs e)
{
var doc = XDocument.Load("C:\\dinamap.xml");
var results = from result in doc.Descendants("Result")
select new
{
Name = (string)result.Attribute("name"),
Value = (string)result.Element("Value"),
Units = (string)result.Element("Units").Attribute("name")
};
foreach (var result in results)
{
MessageBox.Show("{result.Name}: {result.Value} {result.Units}");
}
}

C# deserialize xml using linq

I have the following xml file
<?xml version="1.0" encoding="utf-8"?>
<Launchpad>
<Shortcuts>
<Shortcut Id="1">
<Type>Folder</Type>
<FullPath>C:\bla\bla\bla</FullPath>
<Name>Proximity</Name>
</Shortcut>
<Shortcut Id="2">
<Type>Folder</Type>
<FullPath>C:\bla</FullPath>
<Name>Visual Studio 2017</Name>
</Shortcut>
</Shortcuts>
</Launchpad>
I am trying to deserialize to an object like this: (Tried query syntax first, didn't work either)
XDocument xd = XDocument.Load(FullPath);
// query syntax
//var shortcuts = (from s in xd.Descendants("Shortcuts")
// select new Shortcut()
// {
// Id = Convert.ToInt32(s.Attribute("Id")),
// TypeOfLink = GetTypeFromString(s.Descendants("Type")
// .First()
// .Value),
// FullPathToTarget = s.Descendants("FullPath")
// .First()
// .Value,
// Name = s.Descendants("Name").First().Value,
// }).ToList();
// method syntax
List<Shortcut> shortcuts = xd.Descendants("Shortcuts")
.Select(s =>
new Shortcut()
{
//Id = Convert.ToInt32(s.Attribute("Id")),
TypeOfLink = GetTypeFromString(s.Descendants("Type")
.First().Value),
FullPathToTarget = s.Descendants("FullPath")
.First().Value,
Name = s.Descendants("Name")
.First().Value,
}).ToList();
return shortcuts;
For some reason I only get a single shortcut object in the list. Also, for some reason, the s.Attribute("Id") is null.
If anyone has any suggestions to improve the linq query or why the attribute is not working it would be a great help
You have to read .Descendants("Shortcut") instead of .Descendants("Shortcuts").
Something like this:
List<Shortcut> shortcuts = xd.Descendants("Shortcut").Select(s =>
new Shortcut()
{
Id = s.Attribute("Id").Value,
TypeOfLink = s.Descendants("Type").First().Value,
FullPathToTarget = s.Descendants("FullPath").First().Value,
Name = s.Descendants("Name").First().Value,
}).ToList();
I get the full list by selecting the Shortcut as a descendant of Shortcuts.
Also, ID is an XAttribute so you cant convert it to int.
You need to use Value to get the attributes value.
XDocument xd = XDocument.Load(ms);
XElement root = xd.Document.Root;
var list = root.Descendants("Shortcuts").Descendants("Shortcut").Select(x =>
new Shortcut()
{
Id = Convert.ToInt32(x.Attribute("Id").Value),
TypeOfLink = GetTypeFromString(x.Descendants("Type")
.First().Value),
FullPathToTarget = x.Descendants("FullPath")
.First().Value,
Name = x.Descendants("Name").First().Value
}).ToList();

parsing a xml file which contains more than one keyvalues using c#

I have file format
<?xml version='1.0' encoding='us-ascii'?>
<root>
<file id="001">
<filename>ABC.wav</filename>
<value>0.18</value>
</file>
<file id="002">
<filename>EFG.wav</filename>
<value>0.05</value>
<value>0.14</value>
</file>
</root>
I want to parse that USING C#
doc.Load(confidencethresholdFilePath+"\\model.xml");
XmlNodeList nodes = doc.DocumentElement.SelectNodes("/root/file");
List<Result> results = new List<Result>();
foreach (XmlNode node in nodes)
{
Result result = new Result();
result.ASfilename= node.SelectSingleNode("filename").InnerText;
result.resultedSeconds = node.SelectSingleNode("value").InnerText;
results.Add(result);
}
It gives result but misses the second record's second value.How do i get all results without fail.
How about using LINQ to XML?
var xDoc = XDocument.Load("Input.xml");
var results =
xDoc.Root
.Elements("file")
.Select(f => new
{
FileName = (string)f.Element("filename"),
Values = f.Elements("value").Select(v => (string)v).ToList()
})
.ToList();
results will be a list of anonymous type instances with two properties: FileName:string and Values:List<string>. You can easily change it to return List<Record> instead, just change f => new to f => new Record and update properties info.
As you can see, it's much easier to get XML content using LINQ to XML than using old-style XmlSomething classes.
If you want a separate Result for each value and using your non-Linq style, you could change the initial selection. The file name selection will then need to change appropriately.
doc.Load(confidencethresholdFilePath+"\\model.xml");
XmlNodeList nodes = doc.DocumentElement.SelectNodes("/root/file/value");
List<Result> results = new List<Result>();
foreach (XmlNode node in nodes)
{
Result result = new Result();
result.ASfilename= node.SelectSingleNode("../filename").InnerText;
result.resultedSeconds = node.SelectSingleNode("value").InnerText;
results.Add(result);
}

C# get values from xml attributes

How to get attribute "action" and "filename" values in a right way using C#?
XML:
<?xml version="1.0" encoding="utf-8" ?>
<Config version="1.0.1.1" >
<Items>
<Item action="Create" filename="newtest.xml"/>
<Item action="Update" filename="oldtest.xml"/>
</Items>
</Config>
C#: i cannot get attribute values as well as how to get values in foreach loops? How to solve this?
var doc = new XmlDocument();
doc.Load(#newFile);
var element = ((XmlElement)doc.GetElementsByTagName("Config/Items/Item")[0]); //null
var xmlActions = element.GetAttribute("action"); //cannot get values
var xmlFileNames= element.GetAttribute("filename"); //cannot get values
foreach (var action in xmlActions)
{
//not working
}
foreach (var file in xmlFileNames)
{
//not working
}
Your code example means alot to me. Thanks!
You can use LINQ to XML. Following query returns strongly typed collection of items with Action and FileName properties:
var xdoc = XDocument.Load(#newFile);
var items = from i in xdoc.Descendants("Item")
select new {
Action = (string)i.Attribute("action"),
FileName = (string)i.Attribute("fileName")
};
foreach (var item in items)
{
// use item.Action or item.FileName
}
GetElementsByTagName will find you only direct descendants. The argument is supposed to be just a tag name, not a whole path of elements.
If you want to search across the document while supplying an XPath expression, use SelectNodes instead.
For your document, it should look like this:
var element = (XmlElement)doc.SelectNodes("/Config/Items/Item")[0];
You can achieve what you're asking with LINQ to XML:
// For each element that is a child of your Items element that is named Item
foreach (var item in XElement.Load("file.xml").Descendants("Items").Elements("Item"))
{
// If the element does not have any attributes
if (!item.Attributes().Any())
{
// Lets skip it
continue;
}
// Obtain the value of your action attribute - Possible null reference exception here that should be handled
var action = item.Attribute("action").Value;
// Obtain the value of your filename attribute - Possible null reference exception here that should be handled
var filename = item.Attribute("filename").Value;
// Do something with your data
Console.WriteLine("action: {0}, filename {1}", action, filename);
}
There are a bunch of problems with the code in the question:
1. You are using an XPath in the GetElementsByTagName, just use the tag
2. You are only getting the first XmlNode in the XmlNodeCollection by using [0]
3. Since you only have one XmlNode, you are only getting a string result for getting the attribute, not a collection of strings, which you are then trying to enumerate through
4. Your foreach is broken, there is no type for the resulting object
Here is a snippet that would work:
var doc = new XmlDocument();
doc.Load("test.xml");
var items = doc.GetElementsByTagName("Item");
var xmlActions = new string[items.Count];
var xmlFileNames = new string[items.Count];
for (int i = 0; i < items.Count; i++) {
var xmlAttributeCollection = items[i].Attributes;
if (xmlAttributeCollection != null) {
var action = xmlAttributeCollection["action"];
xmlActions[i] = action.Value;
var fileName = xmlAttributeCollection["filename"];
xmlFileNames[i] = fileName.Value;
}
}
foreach (var action in xmlActions) {
//working
}
foreach (var file in xmlFileNames) {
//working
}
Or, if you don't need all of the actions and filenames in a collection before you act on them, you could just act on each action/filename in the for loop.

Querying xml returns null when using Linq to XML

I have the following xml in a file:
<Person>
<Name first="John" last="Doe" />
</Person>
I loaded the xml document with XDocument.Load, but I can't seem to get the values of the first and last attribute.
I tried:
var q = from n in rq.Element("Name")
select n; //but q is null after this.
Here's an example that should work with your XML file:
var doc = XDocument.Load(...);
var query = from node in doc.Root.Elements("Name")
select new // ↑
{
First = (string)node.Attribute("first"),
Last = (string)node.Attribute("last")
};
foreach (var item in query)
{
Console.WriteLine("{1}, {0}", item.First, item.Last);
}

Categories