linq to xml access data based on field attribute - c#

I have some xml like this:
<Data>
<Rows>
<Row>
<Field Name="title">Mr</Field>
<Field Name="surname">Doe</Field>
<Row>
<Rows>
<Data>
using linq how can I get the value contained in the field element where the attribute is surname
thanks

Here is how you can express your query using LINQ to XML:
XDocument doc = XDocument.Parse("<Data><Rows><Row><Field Name=\"title\">Mr</Field><Field Name=\"surname\">Doe</Field></Row></Rows></Data>");
string[] matches = (from e in doc.Descendants("Field")
where (string)e.Attribute("Name") == "surname"
select (string)e).ToArray();

Actually, you're trying to do an XML-to-Linq thing here. Linq to XML is more meant to create an XML structure from objects through Linq.
Since you have an XML file, you can use something like this:
XmlDocument xml = new XmlDocument();
xml.LoadXml(Content);
string Surname = xml.SelectSingleNode("//Field/[#Name='surname']").Value.ToString();
In other use, to get data from XML, use XPath instead.

Related

How to Select Multiple XML tags as XElement By attatribute value?

How to select Multiple XML Tags as XElement, filtering based on same attribute.
I have Below code i want to select tags with are having action=true
<root>
<first action="true">
<path>E:\Myfolder</path>
</first>
<second>
<path>C:\Users\</path>
</second>
<third action="true">
<name>Mytasks</name>
</third>
</root>
and Output shout be like this
<first action="true">
<path>E:\Myfolder</path>
</first>
<third action="true">
<name>Mytasks</name>
</third>
anybody please help me. I used FirstorDefault() But i am getting only one record among all
Try This .
$(path).find('root').find('[action="true"]')
Try This
xd = XDocument.Load("XML FILE PATH");
xe = xd.Root;
IEnumerable<XElement> oColl = from x in xe.Descendants() where ((string)x.Attribute("action")).equals("true") select x;

Filter XMLNodeList using xPath & Wildcard characters

I have "XML" as below:
<ParentNode>
<ChildNode id="1" Display_Name="ABC"/>
<ChildNode id="2" Display_Name="DEF"/>
<ChildNode id="3" Display_Name="DAX"/>
<ChildNode id="4" Display_Name="LAM"/>
<ChildNode id="5" Display_Name="PKR"/>
<ChildNode id="6" Display_Name="UYA"/>
</ParentNode>
I want to get list of all the Nodes in XMLNodeList in C# using xPath having "A" [regardless of capitals or small] in Display_Name attribute.
What I've tried is:
root.SelectNodes("descendant-or-self::*[contains(#DISPLAY_NAME,'end')]")
Here, root is containing my XML and it is an object of XMLDocument.
Also, how can I make this filter by ignoring either Display_Name is in small letters or capital letters.
"I want to get list of all the Nodes in XMLNodeList in C# using xPath having "A" [regardless of capitals or small] in Display_Name attribute. "
Nature of XML and XPath is case-sensitive. There is no pretty way to do case-insensitive matching using XPath (at least in XPath 1.0, version that is supported by .NET). One known way is using translate() to convert Display_Name value to lower-case before doing further comparison, something like this (see related post) :
var xpath = #"//*[
contains(
translate(#Display_Name
,'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
,'abcdefghijklmnopqrstuvwxyz'
)
,'a'
)
]";
var result = root.SelectNodes(xpath);
Try with below XPath
/ParentNode/ChildNode/#Display_Name
To get result for both
Above XPath will return you all results of ChildNode. Now iterate this XPath to extract all results
Hope it will help you :)
Use OuterXml method.
Try this:
//Load Data
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlString);
//Go the xPath
XmlNode titleNode = xmlDoc.SelectSingleNode(xPath);
//Get the OutXml (You dont need to use a new variable)
string nodeValue = titleNode.OuterXml;
//Load this string as a new XmlDocument and use the second xPath
XmlDocument xmlDoc2 = new XmlDocument();
xmlDoc2.LoadXml(nodeValue);
titleNode = xmlDoc.SelectSingleNode(xPath2);

Insert XML into an XML element

I have a string containing some XML:
<some>
<xml></xml>
<tags/>
<TheData/>
<more>asdf</more>
<of/>
<them></them>
</some>
Instead of <TheData/> we could have <TheData></TheData> or other equivalent forms.
Questions:
1: How can I make sure that the XML does indeed contain an empty TheData element?
2: How can I insert another XML string, HTML encoded into TheData? Example of the other XML:
<mydata>
<name>John</name>
<address>New York City</address>
</mydata>
End result:
<some>
<xml></xml>
<tags/>
<TheData>
<mydata>
<name>John</name>
<address>New York City</address>
</mydata>
</TheData>
<more>asdf</more>
<of/>
<them></them>
</some>
Are there quick ways to do this with e.g. LINQ to XML?
First of all, you have to load your XML into memory as an XDocument instance:
var doc = XDocument.Load(yourFilePath);
Then, you can answer your questions:
1: How can I make sure that the XML does indeed contain an empty TheData element?
var theData = doc.Root.Element("TheData");
if(theData != null && string.IsNullOrEmpty((string)theData))
{
// document contains TheData element which is empty
}
2: How can I insert another XML string, HTML encoded into TheData?
theData.Value = #"<mydata>
<name>John</name>
<address>New York City</address>
</mydata>";
You don't have to bother about XML encoding here. XElement class will take care of that.

Trouble Parsing XML

I am having some trouble parsing some XML from centovacast v3 XML API. I've worked with their 2.x API and parsed it, but the responses have totally changed and I cannot seem to make any of my existing parsers work. Every example I've tried I cannot seem to get at the data correctly.
I'm using .NET 3.5 (4.0 is acceptable as well), any examples would be greatly appreciated.
An example XML document is:
<?xml version=""1.0"" encoding=""UTF-8""?>
<centovacast version=""3.0.0"" host=""0.0.0.0:2199"">
<response type=""success"">
<message>OK</message>
<data>
<row>
<id>1</id>
<parameters>
<ipaddress>127.0.0.1</ipaddress>
<port>2198</port>
<title>Local server</title>
<isrelay>1</isrelay>
<ismaster>1</ismaster>
<defaultip>0.0.0.0</defaultip>
<daemontype>RPC</daemontype>
<hostname/>
</parameters>
<status>
<memfree>101879808</memfree>
<memtotal>1073741824</memtotal>
<memavail>778653696</memavail>
<swapfree>1077501952</swapfree>
<swaptotal>1077501952</swaptotal>
<buffers>172535808</buffers>
<cpuload>0.00</cpuload>
<uptime>13372713</uptime>
<machine>Intel(R) Xeon(R) CPU E5620</machine>
<osbrief>Linux</osbrief>
<osdetails>2.6.18</osdetails>
<other>
<Processes>
<field>n</field>
<field>72</field>
</Processes>
<Kernel>
<field>s</field>
<field>Linux version 2.6.18</field>
</Kernel>
<row>
<field>f</field>
<field>0.000000</field>
</row>
<row>
<field>f</field>
<field>0.000000</field>
</row>
<row>
<field>f</field>
<field>0.000000</field>
</row>
</other>
<online>1</online>
</status>
<accounts>
<licensed>-1</licensed>
<active>1</active>
<inactive>0</inactive>
</accounts>
</row>
</data>
</response>
</centovacast>
I've tried using the following code:
var xml = XDocument.Parse(xmldata);
var query = from p in xml.Descendants("status")
select p;
foreach (var record in query)
MessageBox.Show(record.Value);
but it returns all the data inside the <status> and <parameters> in one big jumble, rather then in separate values.
I would love to serialize / deserialize, as the XML call I'm making returns the above for each server in the cluster, so it could be quite a large result set, but I am not picky, I would be happy just being able to get the data into the correct variables so I can use them.
Here's an example storing some of the elements in an anonymous type:
var data =
XDocument.Parse(xml)
.Root
.Element("response")
.Element("data")
.Elements("row")
.Select(row =>
new
{
Id = Int32.Parse(row.Element("id").Value),
Parameters = new
{
IpAddress = row.Element("parameters").Element("ipaddress").Value,
port = Int32.Parse(row.Element("parameters").Element("port").Value),
},
Status = new
{
MemFree = Int32.Parse(row.Element("status").Element("memfree").Value),
},
});
You can always plug in your own concrete types and null checks where option values might be.
xml.Descendants("status") returns the whole element status together with it's child elements. If you want to enumerate it's elements use the following code:
xml.Descendants("status").Descendants();

Filter document by element attributes using LINQ to XML

I have this XML document :
<?xml version="1.0" encoding="UTF-8"?>
<teryt>
<catalog name="TERC" type="all" date="2010-01-01">
<row>
<field name="Woj">1</field>
<field name="City">Warszawa</field>
<field name="Name">Mazowsze</field>
</row>
<row>
<field name="WojId">1</field>
<field name="City"/>
<field name="Name">Mazowsze</field>
</row>
<row>
<field name="Woj">2</field>
<field name="City"/>
<field name="Name">Slask</field>
</row>
</catalog>
</teryt>
And now I want to get only rows which don't have value in field with attribute City (using LINQ to XML).
Do you mean something like:
var rows = from row in doc.Root.Elements("rows")
where !row.Elements("field")
.Any(x => (string) x.Attribute("name") == "City"
&& x.Value != "")
select row;
That says, "find all rows which don't have any non-empty field elements with a name attribute of City". I think that's what you're after...
Something like:
var query = from row in xdoc.Descendants("row")
where row.Elements("field")
.Any(ff => ff.Attribute("name").Value == "City"
&& String.IsNullOrWhitespace(ff.Value))
select row;
This is predicated on the desire to find every row without a City value.
Once you have loaded your xml document into an XDocument object you can access its tags. So you should grab the Root element of your XDocument and navigate down to the row tags with the Elements method. And when you have all your tags in a collection you can sort out the ones with no city field. I'm almost sure that there is a HasValue property on the xml elements which tells you if it has value or not. But if there isn't one, you can check the Value property which would be empty or null.
So now a little code for this, the way I like:
XDocument doc = XDocument.Load("yourfile");
var tags = doc.Root.Element("catalog")
.Elements("row")
.Where(r=>r.Elements("field")
.Single(f=>f.Attribute("name").Value == "City"
&& string.IsNullOrWhitespace(f.Value)));
It translates into something like this: Take the document, select the root of the document, take the element named "catalog", and give me all the "row" elements, where it is true, that if the "row" has a "field" element with the "name" attribute set to "City", it is null, empty string, or whitespace.
Now this may not be so easy to understand if you are new to this, but this is the way I would do it. You may add a few null-checks but this is up to you now.

Categories