How do I select the element's string of descendant? - c#

How do I select tag "lat" and grab the value "123" base on the "eventid" I want? For example, I want to select <lle:lat>123</lle:lat> of <lle:eventid>ID1</lle:eventid> without using XPath, just LINQ to XML only
Expected output:
123
Below is the xml file:
<soapenv:Letter xmlns:soapenv="http://www.w3.org/2001/12/soap-envelope" soapenv:encodingStyle="http://www.w3.org/2001/12/soap-encoding" >
<soapenv:Body xmlns:lle="http://www.aab.org/lifelogevents" >
<lle:Event>
<lle:eventid>ID1</lle:eventid>
<lle:tweet>
<lle:text>This is some tweet in my day</lle:text>
<lle:location>
<lle:lat>123</lle:lat>
<lle:long>456</lle:long>
</lle:location>
</lle:tweet>
</lle:Event>
<lle:Event>
<lle:eventid>ID2</lle:eventid>
<lle:instagram-post-update>
<lle:text>This is some status update in my day</lle:text>
<lle:location>
<lle:lat>789</lle:lat>
<lle:long>987</lle:long>
</lle:location>
</lle:instagram-post-update>
</lle:Event>
</soapenv:Body>
</soapenv:Letter>
And this is my C# code so far:
XDocument xmldoc = XDocument.Load(#"C:\Users\JACK\source\repos\LINQ_Learn\LINQ_Learn\xmlFile.xml");
XNamespace lle = "http://www.aab.org/lifelogevents";
XNamespace soapenv = "http://www.w3.org/2001/12/soap-envelope";
var lati = from data in xmldoc.Descendants(nlle + "Event")
where (string)data.Element(nlle + "eventid") == "ID1"
select data.Element(nlle + "lat").Value;
foreach(var lat in lati)
{
Console.WriteLine(lat);
}

Here's a solution using Linq to navigate the xml instead. First we get all the descendant "Events", then filter them by the defined "eventid" value and then return their "lat" nodes. FirstOrDefault() returns the first match or the null value if none were found. Finally, the ? symbol serves to return the value of the match only if it isn't null, otherwise it would throw an exception.
var lat = xmldoc.Descendants(lle + "Event")
.Where(x => x.Element(lle + "eventid").Value == "ID1")
.Descendants(lle + "lat")
.FirstOrDefault()?.Value;

Related

How to loop though XElements and compare values using C#

I have an XElement which contains similar nodes but different values.
Like my XElement look like this
<Information>
<Emp>
<A.EMPLID>1</A.EMPLID>
<A.Phone>12##</A.Phone>
</Emp>
<Emp_Add>
<B.ID>125</B.ID>
<Add>XXXXXXX</Add>
</Emp_Add>
<Emp_Add>
<B.ID>1256</B.ID>
<Add>ZZZZZZ</Add>
</Emp_Add>
</Information>
Actually I need to go through each <Emp_Add> node - pick up the value of <B.ID>
and compare it with <Emp>.<A.EMPLID> value. If values are same then display message "Values matched" else message "Values does not match" using C# code.
How to use for each loop and compare for such XElement.
I think you need something like this
See my dotnetfiddle.
var xml =
"<Information>\r\n\t<Emp>\r\n\t\t<A.EMPLID>1</A.EMPLID>\r\n\t\t<A.Phone>12##</A.Phone>\r\n\t</Emp>\r\n\t<Emp_Add>\r\n\t\t<B.ID>125</B.ID>\r\n\t\t<Add>XXXXXXX</Add>\r\n\t</Emp_Add>\r\n\t<Emp_Add>\r\n\t\t<B.ID>1256</B.ID>\r\n\t\t<Add>ZZZZZZ</Add>\r\n\t</Emp_Add>\r\n</Information>";
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml);
XDocument xmlObj = XDocument.Parse(xmlDoc.OuterXml);
var emplId = xmlObj.Descendants().Descendants().Descendants().FirstOrDefault().Value;
var empsAdd = xmlObj.Descendants().Descendants().Where(d => d.Name.LocalName == "Emp_Add");
foreach (var emp in empsAdd)
{
var currentEmpIdNode = emp.Descendants().FirstOrDefault();
Console.WriteLine(currentEmpIdNode != null && currentEmpIdNode.Value == emplId
? "Values matched"
: "Values does not match");
}

Linq statement in C# to extract data from XElement

I have a List containing elements like this:
{<d:element m:type="SP.KeyValue" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices">
<d:Key>Path</d:Key>
<d:Value>https://my.home.site.com</d:Value>
<d:ValueType>Edm.String</d:ValueType>
</d:element>}
I'd like help to discern the Linq statement required to extract only the "https://my.home.site.com" values from said List<>. The catch here is that we cannot only use the <d:Value> because only XElements in this list that has a <d:Key> value of Path, like in the example above, actually contain URLs in the <d:Value> key.
Does anyone know the magic Linq statement that would perform said data extract?
Assuming your data is coming from an XML file similar to this:
<?xml version="1.0"?>
<root xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices">
<d:element m:type="SP.KeyValue">
<d:Key>Path</d:Key>
<d:Value>https://my.home.site.com</d:Value>
<d:ValueType>Edm.String</d:ValueType>
</d:element>
<d:element m:type="SP.KeyValue">
<d:Key>NotPath</d:Key>
<d:Value>https://my.home.site.com</d:Value>
<d:ValueType>Edm.String</d:ValueType>
</d:element>
</root>
The following code:
XElement root = XElement.Load("Some file");
List<string> urls;
//Query Syntax
urls = (from e in root.Elements(d + "element")
where e.Element(d + "Key").Value == "Path"
select e.Element(d + "Value").Value);
//Or
//Method Syntax
urls = (from e in root.Elements(d + "element")
where e.Element(d + "Key").Value == "Path"
select e.Element(d + "Value").Value).ToList();
Console.WriteLine(string.Join(",", urls));
Will result in (note that it ignores the "NotPath" key):
https://my.home.site.com
You can check out a live example here and check out this for more XElement information.
if you actually have a List of XElement:
var list = new List<XElement>(); //however you get your XElement collection
var values = list.Where(x => x.Elements().First(e => e.Name.LocalName == "Key").Value == "Path")
.Select(x => x.Elements().First(e => e.Name.LocalName == "Value").Value)
if you have an XDocument, you'd just modify the beginning of the query slightly.
I think that problem if with naespace declaration. Try this:
string xml = "<d:element m:type=\"SP.KeyValue\" xmlns:m=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\" xmlns:d=\"http://schemas.microsoft.com/ado/2007/08/dataservices\">"+
"<d:Key>Path</d:Key>"+
"<d:Value>https://my.home.site.com</d:Value>"+
"<d:ValueType>Edm.String</d:ValueType>"+
"</d:element>";
XDocument xmlObj = XDocument.Parse(xml);
XNamespace ns_d = "http://schemas.microsoft.com/ado/2007/08/dataservices";
var result = xmlObj.Descendants(ns_d + "Value").Select(x => x.Value);

How to get the node value of the name space 'xsi:type' from xml data?

I have some xml data taken into a XDocument say 'xDoc' which is of the following format
<uketd_dc:uketddc xsi:schemaLocation ="http://naca.central.cranfield.ac.uk/ethos-oai/2.0/ http://naca.central.cranfield.ac.uk/ethos-oai/2.0/uketd_dc.xsd">
<dc:identifier>
http://www.google.com
</dc:identifier>
<dc:language>
en
</dc:language>
<dc:name>
Some name
</dc:name>
<dc:identifier xsi:type="dcterms:URI">
http://zzzz.com/zz.pdf?sequence=1
</dc:identifier>
</uketd_dc:uketddc>
I can get the value of 'dc:language' and 'dc:name' nodes using the below query
var values= from e in xDoc.Descendants(uketd_dc + "uketddc")
select new Item(
e.Element(dc + "language").Value,
e.Element(dc + "name").Value
);
The problem is how to get the value of the last node?
<dc:identifier xsi:type="dcterms:URI">
http://zzzz.com/zz.pdf?sequence=1
</dc:identifier>
Presuming you just want the value for the first identifier that has that type attribute:
var uri = (string)e.Elements(dc + "identifier")
.Where(e => (string)e.Attribute(xsi + "type") == "dcterms:URI")
.FirstOrDefault()
Where xsi is the namespace for the prefix xsi, which should be as below:
XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance";

Linq to XML Descendants can't read part of xml

I have XML document like this
<document>
<indexroot>
<type>type</type>
<model>model</model>
</indexroot>
<root>
<model_type1>model type 1</model_type1>
<model_type2>model type 2</model_type2>
</root>
</document>
And a linq to xml code:
var elements = (from element in pdb.Descendants()
select new
{
type = (string)element.Element("type") ?? "-",
model= (string)element.Element("model") ?? "-",
model_type1= (string)element.Element("model_type1") ?? "-",
model_type2= (string)element.Element("model_type2") ?? "-"
}).FirstOrDefault();
I get type and a model variables, but it seems I can't reach model_type1 and model_type2, now I understand that this happens because indexroot and root tags, amd if I seperate those tags into diffrent linq to xml code blocks with Descendants("indexroot") and Descendants("root"), everything works fine, but I wan't them in one block, is it possible to achieve that, and how?
You need to navigate down the XML heirarchy for each element you are trying to extract.
This is because the Element method only looks at direct children, not all descendants of a node. From the documentation:
Gets the first (in document order) child element with the specified XName.
One implementation using just Linq-to-XML might be:
xml = "<document>" +
"<indexroot>" +
" <type>type</type>" +
" <model>model</model>" +
"</indexroot>" +
"<root>" +
" <model_type1>model type 1</model_type1>" +
" <model_type2>model type 2</model_type2>" +
"</root>" +
"</document>";
XDocument doc = XDocument.Parse(xml);
var newItem = (from element in doc.Descendants("document")
select new
{
Type = (string)element.Element("indexroot").Element("type") ?? "-",
Model = (string)element.Element("indexroot").Element("model") ?? "-",
ModelType1 = (string)element.Element("root").Element("model_type1") ?? "-",
ModelType2 = (string)element.Element("root").Element("model_type2") ?? "-",
}).FirstOrDefault();
Console.WriteLine(newItem);

Why can't I get the specific node under some condition?

Why doesn't this xpath work with me? I want the current title if the language _id =2
./title[language_id=2]
<news pnumber="1" id="1"><event_id>578</event_id><event_type_id>1</event_type_id><language_id>2</language_id><title>meeting</title></news>
<news pnumber="1" id="1"><event_id>578</event_id><event_type_id>1</event_type_id><language_id>1</language_id><title>meeting</title></news>
The correct XPath expression is
//title[../language_id=2]
To avoid the reverse axis, use:
self::*[language_id=2]/title.
First add root to your XML then:
XDocument doc = XDocument.Load(xmlFilePath);
var result= doc.Descendants("news")
.Where(x=>x.Attribute("id") != null && x.Attribute("id").Value = "1")
.Select(x=>x.Descendants("title").First().Value);
Here is description of this linq2xml:
First Load XML file (Also you can parse xml string):
XDocument.Load(xmlFilePath);
Find your news elements :
doc.Descendants("news")
Between news elements select elements which has id=1:
Where(x=>x.Attribute("id") != null && x.Attribute("id").Value = "1")
From each filtered item select first title:
x.Descendants("title").First().Value

Categories

Resources