How can i fetch the 'Value' from the keyvalue pair using c# - c#

I would like to fetch the string mentioned in 'Value' for various parameter available under 'Name' using c#.
Here is my current xml as follows:
<DrWatson>
<Sets>
<Set>
<APIParameters>
<Parameter Name="SID_STAGE" Value="101198" Required="true" />
<Parameter Name="SID_QE" Value="Test 91817" Required="true" />
</APIParameters>
</Set>
</Sets>
</DrWatson>
I would like to fetch the '101198' available under 'Value' for Name = SID_STAGE.
Please suggest how can i perform it.

You can parse parameters dictionary (that is natural way to store key-value pairs) with LINQ to XML:
var xdoc = XDocument.Load(path_to_xml);
var parameters = xdoc.Descendants("Parameter")
.ToDictionary(p => (string)p.Attribute("Name"),
p => (string)p.Attribute("Value"));
var stage = parameters["SID_STAGE"];
Keep in mind, that you should check if parameter exists in dictionary before getting it (if it is possible that parameter can not be in your xml):
if (parameters.ContainsKey("SID_STAGE"))
// get parameter value
Also with XPath you can make query more concrete (if it is possible that somewhere will be another Parameter elements):
var xpath = "DrWatson/Sets/Set/APIParameters/Parameter";
var parameters = xdoc.XPathSelectElements(xpath)
.ToDictionary(p => (string)p.Attribute("Name"),
p => (string)p.Attribute("Value"));

var result = XElement.Parse(xmlString)
.Descendants("Parameter")
.First(node => (string)node.Attribute("Name") == "SID_STAGE")
.Attribute("Value");
Console.WriteLine(result.Value); //prints 101198
Will throw an exception of element with this attribute is absent. Consider using FirstOrDefault if you would like another behaviour.

Use a LINQ to XML query:
var xml = XDocument.Load("path...");
var foo = (from n in xml.Descendants("APIParameters")
where n.Element("Parameter").Attribute("Name").Value == "SID_STAGE"
select n.Element("Parameter").Attribute("Value").Value).FirstOrDefault();
Gives:
101198

using System;
using System.Xml.Linq;
using System.Web;
namespace YourProjectName
{
public static class XmlFileRetrieve
{
public static string GetParameterValue(string name)
{
try
{
string path = HttpContext.Current.Server.MapPath("~/YourFolderName/YourXmlFileName.xml");
XDocument doc = XDocument.Load(path);
if (!(doc == null))
{
var parameter = (from el in doc.Root.Elements("Parameter")
where (string)el.Attribute("Name") == name
select (string)el.Attribute("value")).Select(keyvalue => new { name = keyvalue }).Single(); ;
return parameter.name;
}
return "";
}
catch (Exception e)
{string error=e.Message;return "";
}
}
}
}

Related

XML Key value paire C#

This is my XDocument
<grantitem adnidtype="306" xmlns="http://tempuri.org/">
<attribute key="AccountNumber" value="1111" />
<attribute key="DateofMeterRead" value="20161226" />
<attribute key="Arrears" value="11.11" />
<attribute key="MeterRead" value="11111" />
</grantitem>
I am trying to read this by using
var q = from b in doc.Descendants("grantitem")
select new
{
key= (string)b.Element("attribute key") ?? tring.Empty,
value= (string)b.Element("value") ?? String.Empty
};
But ist return a null value. Can anyone see some missing?
There are a couple of problems here:
You're trying to fetch elements with a name of grantitem in no namespace, whereas your element is actually in a namespace of http://tempuri.org/
You're trying to retrieve attributes as if they were elements. You need to retrieve the attribute child elements of grantitem and then retrieve the key/value attributes of those elements
Here's an example which does what you want:
using System;
using System.Linq;
using System.Xml.Linq;
class Test
{
static void Main()
{
var doc = XDocument.Load("test.xml");
XNamespace ns = "http://tempuri.org/";
var query = doc
.Descendants(ns + "grantitem")
.Elements(ns + "attribute")
.Select(x => new {
Key = (string) x.Attribute("key") ?? "",
Value = (string) x.Attribute("value") ?? ""
});
foreach (var item in query)
{
Console.WriteLine(item);
}
}
}
You might consider using creating KeyValuePair<string, string> values instead of using an anonymous type.
Note that this is geared towards being able to find multiple grantitem elements anywhere in the doc. If the reality is that there's always a single grantitem element and it's always the root element, I'd probably use doc.Root.Elements(ns + "attribute") instead of using Descendants first.
I like doing this with a dictionary :
Dictionary<string,string> dict = from b in doc.Descendants("grantitem").FirstOrDefault().Elements("attribute").GroupBy(x => (string)x.Attribute("key"), y => (string)y.Attribute("value"))
.ToDictionary(x => x.Key, y => y.FirstOrDefault());

Parsing a xml string & retrieving its attribute Value using Linq to XML C#

I am quite new to Linq to XML & trying to Parse a xml string & retrieve its attribute Value using Linq to XML in C#.
My XML string looks like :
<configuration xmlns:lui="http://www.xyz.com/UITags">
<pub id="pubId1" lang="en-US">
<configitem name="visible" value="visible"/>
<configitem name="working_status" value="unlocked"/>
<configitem name="prepared" value="prepared"/>
</pub>
.....
.....
<pub id="Pub2" lang="es-XM">...</pub>
....
....
</configuration>
I want to fetch the value of 'id' & 'lang' from pub node & value of attribute named 'working_status' from configitem Node.
Now as I am getting the above xml as a string parameter (i.e. myXmlData), by doing
XmlDocument doc = new XmlDocument();
doc.LoadXml(myXmlData);
XmlNodeList publicationsNodeList = doc.SelectNodes("//configuration/pub");
...
...
Then I have to loop through using foreach, which I want to avoid as much as possible.
Can anyone help me how to achieve this using Linq to XML in C#, rather then conventional way.
Following LINQ to XML query will return sequence of anonymous objects with id, lang, and working status of pub elements:
var xdoc = XDocument.Parse(myXmlData);
var query =
from p in xdoc.Root.Elements("pub")
let ws = p.Elements("configitem")
.FirstOrDefault(c => (string)c.Attribute("name") == "working_status")
select new {
Id = (string)p.Attribute("id"),
Lang = (string)p.Attribute("lang"),
WorkingStatus = (ws == null) ? null : (string)ws.Attribute("value")
};
For your sample xml it returns two objects with following data:
{
Id = "pubId1",
Lang = "en-US",
WorkingStatus = "unlocked"
},
{
Id = "Pub2",
Lang = "es-XM",
WorkingStatus = null
}
var query = from x in xdoc.Descendants("pub")
select new
{
Id = (string)x.Attribute("id"),
Lang = (string)x.Attribute("lang"),
Name = x.Descendants("configitem").Select(y => y.Attribute("name").Value).FirstOrDefault(y => y == "working_status")
};

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;

Best way to query XDocument with LINQ?

I have an XML document that contains a series of item nodes that look like this:
<data>
<item>
<label>XYZ</label>
<description>lorem ipsum</description>
<parameter type="id">123</parameter>
<parameter type="name">Adam Savage</parameter>
<parameter type="zip">90210</parameter>
</item>
</data>
and I want to LINQ it into an anonymous type like this:
var mydata =
(from root in document.Root.Elements("item")
select new {
label = (string)root.Element("label"),
description = (string)root.Element("description"),
id = ...,
name = ...,
zip = ...
});
What's the best way to pull each parameter type according to the value of its 'type' attribute? Since there are many parameter elements you wind up with root.Elements("parameter") which is a collection. The best way I can think to do it is like this by method below but I feel like there must be a better way?
(from c in root.Descendants("parameter") where (string)c.Attribute("type") == "id"
select c.Value).SingleOrDefault()
I would use the built-in query methods in LINQ to XML instead of XPath. Your query looks fine to me, except that:
If there are multiple items, you'd need to find the descendants of that instead; or just use Element if you're looking for direct descendants of the item
You may want to pull all the values at once and convert them into a dictionary
If you're using different data types for the contents, you might want to cast the element instead of using .Value
You may want to create a method to return the matching XElement for a given type, instead of having several queries.
Personally I don't think I'd even use a query expression for this. For example:
static XElement FindParameter(XElement element, string type)
{
return element.Elements("parameter")
.SingleOrDefault(p => (string) p.Attribute("type") == type);
}
Then:
var mydata = from item in document.Root.Elements("item")
select new {
Label = (string) item.Element("label"),
Description = (string) item.Element("description"),
Id = (int) FindParameter(item, "id"),
Name = (string) FindParameter(item, "name"),
Zip = (string) FindParameter(item, "zip")
};
I suspect you'll find that's neater than any alternative using XPath, assuming I've understood what you're trying to do.
use XPATH - it is very fast ( except xmlreader - but a lot of if's)
using (var stream = new StringReader(xml))
{
XDocument xmlFile = XDocument.Load(stream);
var query = (IEnumerable)xmlFile.XPathEvaluate("/data/item/parameter[#type='id']");
foreach (var x in query.Cast<XElement>())
{
Console.WriteLine( x.Value );
}
}

How to get an element that has : in its name?

I need to get the CountryName from this XML: http://api.hostip.info/?ip=12.215.42.19
The response XML is:
<HostipLookupResultSet version="1.0.1"
xmlns:gml="http://www.opengis.net/gml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://www.hostip.info/api/hostip-1.0.1.xsd">
<gml:description>This is the Hostip Lookup
Service</gml:description>
<gml:name>hostip</gml:name>
<gml:boundedBy>
<gml:Null>inapplicable</gml:Null>
</gml:boundedBy>
<gml:featureMember>
<Hostip>
<ip>12.215.42.19</ip>
<gml:name>Sugar Grove, IL</gml:name>
<countryName>UNITED STATES</countryName>
<countryAbbrev>US</countryAbbrev>
<!-- Co-ordinates are available as lng,lat -->
<ipLocation>
<gml:pointProperty>
<gml:Point srsName="http://www.opengis.net/gml/srs/epsg.xml#4326">
<gml:coordinates>-88.4588,41.7696</gml:coordinates>
</gml:Point>
</gml:pointProperty>
</ipLocation>
</Hostip>
</gml:featureMember>
</HostipLookupResultSet>
Problem is I can't include : in the Descendants method because it throws:
XmlException: The ':' chracater,
hexadecimal value 0x3A, cannot be
included in a name.
Thanks
try this
var descendants = from i in XDocument.Load(xml).Descendants("Hostip")
select i.Element("countryName");
Update
complete code for downloading the xml and finding the name of countryName
string xml;
using(var web = new WebClient())
{
xml = web.DownloadString("http://api.hostip.info/?ip=12.215.42.19");
}
var descendants = from i in XDocument.Parse(xml).Descendants("Hostip")
select i.Element("countryName");
A small example on how to apply namespaces in LINQ to XML:
XElement doc = XElement.Load("test.xml");
XNamespace ns = "http://www.opengis.net/gml";
var firstName = doc.Descendants(ns + "name").First().Value;
You need to reference the gml namespace; once you've done that you should be able to navigate using the tag names that appear to the right of "gml:"
UPDATE
I'm not sure what context you're applying this to, but here's a sample console app that works:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
namespace LinqToXmlSample
{
class Program
{
static void Main(string[] args)
{
XElement x = XElement.Load("http://api.hostip.info/?ip=12.215.42.19");
foreach (XElement hostip in x.Descendants("Hostip"))
{
string country = Convert.ToString(hostip.Element("countryName").Value);
Console.WriteLine(country);
}
Console.ReadLine();
}
}
}
var gml = (XNamespace)"http://www.opengis.net/gml";
var doc = XDocument.Load(...) or XDocument.Parse(...);
var name = doc.Descendants(gml + "featureMember").Descendants("countryName").First().Value;
Or you could go brute force and strip all the namespaces:
void RemoveNamespace(XDocument xdoc)
{
foreach (XElement e in xdoc.Root.DescendantsAndSelf())
{
if (e.Name.Namespace != XNamespace.None)
{
e.Name = XNamespace.None.GetName(e.Name.LocalName);
}
if (e.Attributes().Any(a => a.IsNamespaceDeclaration || a.Name.Namespace != XNamespace.None))
{
e.ReplaceAttributes(e.Attributes().Select(a => a.IsNamespaceDeclaration ? null : a.Name.Namespace != XNamespace.None ? new XAttribute(XNamespace.None.GetName(a.Name.LocalName), a.Value) : a));
}
}
}

Categories

Resources