How to get value from XML file - c#

Given the following XML file:
<root>
<country>
<name></name>
<locationOU>null</location>
</country>
<country>
<name>Sweden</name>
<locationOU>Some Value</locationOU>
</country>
<country>
<name>Lithuania</name>
<locationOU>Some Value</locationOU>
</country>
<country>
<name>Belgium</name>
<locationOU>Some Value</locationOU>
</country>
</root>
How do I get the value of locationOU based on name value eg. name = Sweden?

You can work with XPath via XPathSelectElement(XNode, String).
using System.Xml.Linq;
using System.Xml.XPath;
// Read XML file
XDocument root = XDocument.Load(/* Your XML file path */);
// Read XML from string
// XDocument root = XDocument.Parse(xml);
XElement result = root.XPathSelectElement("/root/country[name='Sweden']");
string locationOU = result.Element("locationOU").Value;
Demo # .NET Fiddle

I like using xml linq with a dictionary :
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication40
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
Dictionary<string, string> dict = doc.Descendants("country")
.GroupBy(x => (string)x.Element("name"), y => (string)y.Element("locationOU"))
.ToDictionary(x => x.Key, y => y.FirstOrDefault());
string sweedenLocation = dict["Sweden"];
}
}
}

XDocument doc = XDocument.Parse(XML_TEXT);
XElement rootElement = doc.XPathSelectElement("root");
var countries = rootElement?.Descendants().Where(e => e.Name.LocalName.Equals("country"));
var yourCountry = countries.Descendants().FirstOrDefault(d => d.Name.LocalName.Equals("locationOU") && d.Value == "Sweden");

You can use XPath with above answers #Yong Shun
Or You can use DataSet as bellow:
DataSet ds=new DataSet();
ds.readXml(filename);
DataTable dt=ds.Tables[0];
string name="Sweden";
foreach(DataRow dr in dt.Select(String.Format("name='{0}'",name))
{
string locationOU=dr["locationOU"].toString();
}

Related

Getting values of both attribute and element in an xml

I have the following xml
<lists>
<list Group="3">More_lists_go_here</list>
</lists>
What I want is both the list element value which is More_lists_go_here and the Group attribute value which is 3.
What I have tried so far is
XmlDocument doc = new XmlDocument();
doc.LoadXml("<list Group=\"3\">More_lists_go_here</list>");
XmlElement root = doc.DocumentElement;
string value = root.Descendants("lists").Elements("list").Select(x => (string)x.Attribute("Group")).ToList();
what that gets me is
value = 3
what I want is both 3 and More_lists_go_here for string value
Use xml linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication40
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
string input = "<lists><list Group=\"3\">More_lists_go_here</list></lists>";
XDocument doc = XDocument.Parse(input);
var results = doc.Descendants("list").Select(x => new { group = (string)x.Attribute("Group"), value = (string)x }).ToList();
}
}
}

Convert XML to formatted plain text issue

I have the following XML and i want to convert the contents to something along the lines of the following format.
PatientId: 123455, IdScheme: Test ....
<?xml version="1.0"?>
<gls:TheDocument xmlns:pbr="http://www.something.com"
xmlns:gls="http://www.testsomething.com"
xmlns:cnr="http://www.organisation.com"
xmlns:h="http://www.w3.org/1999/xhtml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" schemaVersion="2.8">
<gls:PatientDem>
<cnr:PatientId>
<cnr:IdValue>123455</cnr:IdValue>
<cnr:IdScheme>TEST</cnr:IdScheme>
<cnr:IdType>PRN</cnr:IdType>
</cnr:PatientId>
<cnr:PatientName>
<cnr:Name>
<cnr:Title>Mr</cnr:Title>
<cnr:GivenName>Joe</cnr:GivenName>
<cnr:FamilyName>Wood</cnr:FamilyName>
</cnr:Name>
<cnr:NameType>Current Name</cnr:NameType>
</cnr:PatientName>
<cnr:PatientAddress>
<cnr:Address>
<cnr:AddressLine>57 High Street</cnr:AddressLine>
<cnr:AddressLine>London</cnr:AddressLine>
</cnr:Address>
<cnr:PostCode>WC1E 7HU</cnr:PostCode>
<cnr:AddressType>Current Residence</cnr:AddressType>
</cnr:PatientAddress>
<cnr:DateOfBirth>1969-11-02</cnr:DateOfBirth>
<cnr:Sex>M</cnr:Sex>
</gls:PatientDem>
<pbr:PatientAdminRef>
<pbr:Referrer>
<pbr:RefGP>
<cnr:GpcpName>
<cnr:FullName>DR SMITH</cnr:FullName>
</cnr:GpcpName>
<cnr:TheOrganisation>
<cnr:OrganisationId>
<cnr:IdValue>52522</cnr:IdValue>
<cnr:IdScheme>PracticeID</cnr:IdScheme>
<cnr:IdType>Healthcare Organisation</cnr:IdType>
</cnr:OrganisationId>
<cnr:OrganisationName>National Health
Service</cnr:OrganisationName>
<cnr:OrganisationAddress>
<cnr:TheAddress>
<cnr:AddressLine1>Centre House</cnr:AddressLine1>
<cnr:AddressLine2>799 Chichester
Street</cnr:AddressLine2>
<cnr:AddressLine3>London</cnr:AddressLine3>
</cnr:TheAddress>
<cnr:AddressType>Practice Address</cnr:AddressType>
</cnr:OrganisationAddress>
<cnr:OrganisationTelecom>
<cnr:TelephoneNumber>016190542350</cnr:TelephoneNumber>
<cnr:TeleType>Voice</cnr:TeleType>
</cnr:OrganisationTelecom>
</cnr:TheOrganisation>
</pbr:RefGP>
</pbr:Referrer>
</pbr:PatientAdminRef>
</gls:TheDocument>
So is it possible to do this? I had a go at doing this but I know for a fact i am doing it wrong as it cannot produce the result i want so any help will be much appreciated:
C# Code
XDocument doc = XDocument.Parse(xml);
XElement root = doc.Root;
XNamespace glsNs = root.GetNamespaceOfPrefix("gls");
XNamespace cnrNS = root.GetNamespaceOfPrefix("cnr");
XNamespace pbrNS = root.GetNamespaceOfPrefix("pbr");
var output = new StringBuilder();
foreach (var result in doc.Descendants(gls + "PatientDem").Select(x => new {
Key = (string)x.Name.LocalName,
Value = x.Value
}))
{
output.AppendLine($"{result.key} : {result.value}");
}
Try following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication108
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
XElement root = doc.Root;
XNamespace cnrNs = root.GetNamespaceOfPrefix("cnr");
var results = doc.Descendants(cnrNs + "PatientId").Select(x => new {
value = (string)x.Element(cnrNs + "IdValue"),
scheme = (string)x.Element(cnrNs + "IdScheme")
}).ToList();
}
}
}

How to find attributes and their values in an XML without the name?

I'm new to C#
Here the xml:
<ROOT>
<Columns BaseXPath="//Orders/Position/">
<Colum XPath="#PositionSK" Name="Position"/>
<Colum XPath="#PosGroup" Name="Gruppen-Nr"/>
<Colum XPath="#PosNumber" Name="PositionsNr"/>
<Colum XPath="#PositionCommercialTypeSK" Name="Status"/>
<Colum XPath="#BundlePositionSK" Name="BundlePositionSK"/>
<Colum XPath="#MainPositionSK" Name="MainPositionSK"/>
<Colum XPath="#SalesAgentPrice" Name="Preis"/>
<Colum XPath="#BookingUnitSK" Name="Buch"/>
<Colum XPath="#ContentComponentCommSK" Name="IKO"/>
<Colum XPath="#PositionTypeSK" Name="PositionsTyp"/>
<Colum XPath="//Advertisement[#AdvertisementSK = PositionAdvertisementRelationship/#AdvertisementSK]/#AdvertisementSK" Name="AdvertisementSK"/>
<Colum XPath="//Advertisement[#AdvertisementSK = PositionAdvertisementRelationship/#AdvertisementSK]/#AdvertisementTypeSK" Name="Formatvorgabe"/>
</Columns>
</ROOT>
This xml can always change. So its never the same. Sometimes there are more infos, sometimes less.
This xml give me the certain info, which should be searched in the second "main xml".
So now I know that I have to find the Attribute of PositionSK, PosGroup, PositionCommercialTypeSK, ... . In the other xml.
But how can I do this? The name is never the same, so I need a placeholder for them?
I tried this:
public class ResultNames
{
XmlDocument xml = new XmlDocument();
public List<ResultNames> GetRightNames (string file)
{
xml.Load(file); //this is the xml file
var list = xml.SelectNodes("//ROOT/Columns/Colum");
foreach ( XmlNode colum in list)
{
XmlNode bla = colum.Attributes; //I dont know what I can do here, without any name.
}
return null;
}
and what is with the other xml file, do I need an extra class?
A small sample from the other xml:
<Set>
<Orders OrderSK="0013233309" OrderTypeSK="ORDER" OrderDate="2000-01-01T12:00:00" OrderPrice="0.0000" OrderQuantity="0.00" DistrictSK="0026070180" PaymentTypeSK="E" OrderCreationTypeSK="SNW5ORD" SalesAgentSK="0020025518" ChangeDate="2018-01-25T15:48:29" SalesOrganisationSK="K10-100-1000-50-65" ChangeDateFS="2017-12-11T15:25:21" Source="CORE" Status="C">
<Position PosNumber="3" PosGroup="5" PositionTypeSK="ONL" PositionCommercialTypeSK="DEFAULT"
But its a lot bigger.
Use Xml Linq along with a dictionary
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME1 = #"c:\temp\test.xml";
const string FILENAME2 = #"c:\temp\test1.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME1);
Dictionary<string, XElement> dict = doc.Descendants("Columns").FirstOrDefault().Elements()
.GroupBy(x => (string)x.Attribute("XPath"), y => y)
.ToDictionary(x => x.Key, y => y.FirstOrDefault());
XDocument order = XDocument.Load(FILENAME2);
List<XElement> positions = order.Descendants("Position").ToList();
foreach (XElement position in positions)
{
foreach (XAttribute attribute in position.Attributes())
{
string name = attribute.Name.LocalName;
string value = (string)attribute;
XElement element = dict["#" + name];
element.SetValue(value);
}
}
}
}
}
Code below just gets the Name from first Xml file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME1 = #"c:\temp\test.xml";
const string FILENAME2 = #"c:\temp\test1.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME1);
Dictionary<string, string> dict = doc.Descendants("Columns").FirstOrDefault().Elements()
.GroupBy(x => (string)x.Attribute("XPath"), y => (string)y.Attribute("Name"))
.ToDictionary(x => x.Key, y => y.FirstOrDefault());
XDocument order = XDocument.Load(FILENAME2);
List<XElement> positions = order.Descendants("Position").ToList();
foreach (XElement position in positions)
{
foreach (XAttribute attribute in position.Attributes())
{
string name = attribute.Name.LocalName;
string value = (string)attribute;
if(dict.ContainsKey("#" + name))
{
string xName = dict["#" + name];
Console.WriteLine("Key = '{0}', Name = '{1}'", name, xName);
}
else
{
Console.WriteLine("Not in dictionary : Key = '{0}'", name);
}
}
}
}
}
}
I had to make some assumptions about the data you are working with, since you haven't provided examples of everything.
The first assumption is the format of the 2nd XML document. I had to guess from the format of the first document.
The 2nd assumption is that that XPATHs specified in the 1st document Colum elements always point to an Attribute.
void Main()
{
string xml1 =
#"<ROOT>
<Columns BaseXPath=""//Orders/Position/"">
<Colum XPath=""#PositionSK"" Name=""Position""/>
<Colum XPath=""#PosGroup"" Name=""Gruppen-Nr""/>
</Columns>
</ROOT>";
string data =
#"<Set>
<Orders>
<Position PositionSK=""A"" PosGroup=""1"" SomeOtherAttribute=""ABC"" />
<Position PositionSK=""B"" PosGroup=""2"" SomeOtherAttribute=""DEF"" />
</Orders>
</Set>";
var schemaDoc = XDocument.Parse(xml1);
var dataDoc = XDocument.Parse(data);
var itemsXPath = schemaDoc.Descendants("Columns").FirstOrDefault()?.Attribute("BaseXPath").Value;
var basePath = schemaDoc.Descendants("Columns").FirstOrDefault().Attribute("BaseXPath").Value;
// XPATH isn't supposed to end with a trailing "/".
if (basePath.EndsWith("/"))
{
basePath = basePath.Substring(0, basePath.Length - 1);
}
var lines = dataDoc.XPathSelectElements(basePath);
var rowIndex = 0;
foreach (var line in lines)
{
Console.WriteLine($"---Row {rowIndex}");
foreach (var col in schemaDoc.Descendants("Colum"))
{
var columnName = col.Attribute("Name").Value;
Console.Write($"{columnName}: ");
var columnValue = ((XAttribute)((IEnumerable<Object>)line.XPathEvaluate(col.Attribute("XPath").Value)).FirstOrDefault()).Value;
Console.WriteLine(columnValue);
}
Console.WriteLine();
rowIndex++;
}
}
This produces the following output:
---Row 0
Position: A
Gruppen-Nr: 1
---Row 1
Position: B
Gruppen-Nr: 2
You can change the attributes that are output by adjusting the content of xml1.

How to get XmlElement from XmlNodeList in C#?

Below is sample of my XML file
<?xml version="1.0" encoding="UTF-8"?>
<summary>
<testresult>
<result value="10" name="long">100</result>
<result value="12" name="short">200</result>
<result value="14" name="long">300</result>
</testresult>
<testresult>
<result value="10" name="short">50</result>
<result value="12" name="short">60</result>
<result value="14" name="long">70</result>
</testresult>
</summary>
I need to get attribute values for result elements.
I done it using foreach loop as below.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(item.Value);
XmlNodeList nodelist = xmlDoc.SelectNodes("//testresult");
for (int i = 0; i < nodelist.Count; i++)
{
foreach (XmlElement child in nodelist[i])
{
if (child.HasAttributes)
{
result.Add(child.Attributes["value"].Value); //This is working fine.
}
}
}
My ultimate goal is to identify the name and get value if name = "long" only.
for that I need to get the value of name Attribute.
I need to do that without using foreach loop. Any suggestion to achieve my task inside the for loop ?
Thanks.
You could parse your xml easy with XDocument:
var xDoc = XDocument.Load(#"YourXmlFile");
var result = xDoc.Descendants("result")
.Where(x=>x.Attribute("name").Value=="long")
.Select(x=>x.Value);
If you can use LINQ to XML then you even can get results as integers
var xdoc = XDocument.Load(item.Value);
var results = from r in xdoc.Descendants("result")
where (string)r.Attribute("name") == "long"
select (int)r.Attribute("value");
Output:
[10, 14, 14]
If you have to use XmlDocument
var result = from XmlElement tr in xmlDoc.SelectNodes("//testresult")
from XmlElement r in tr
where r.Attributes["name"].Value == "long"
select r.Attributes["value"].Value;
You can also provide more preciese XPath
var result = from XmlElement r in xmlDoc.SelectNodes("//testresult/result[#name='long']")
select r.Attributes["value"].Value;
Using xml linq to get all the values
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication43
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
var results = doc.Descendants("testresult").Select(x => new {
result = x.Elements("result").Select(y => new {
value = (int)y.Attribute("value"),
name = (string)y.Attribute("name"),
text = (int)y
}).ToList()
}).ToList();
}
}
}

Read XML NodeList

I am trying to parse an XML response from a REST call. I can read the XML just fine with my stream reader but when I try to select the first node, it brings back nothing. Here is my XML:
<?xml version="1.0" encoding="UTF-8" standalone="true"?>
<slot_meta_data xmlns:ns2="http://www.w3.org/2005/Atom">
<product id="MDP">
<name>MDP</name>
</product>
<product id="CTxP">
<name>CTxP</name>
</product>
<product id="STR">
<name>STR</name>
</product>
<product id="ApP">
<name>ApP</name>
<slot>
<agent_id>-1111</agent_id>
<agent_name>ApP</agent_name>
<index_id>-1</index_id>
<alias>App Alias</slot_alias>
</slot>
</product>
<product id="TxP">
<name>TxP</name>
<slot>
<agent_id>2222</agent_id>
<agent_name>App2</agent_name>
<index_id>-1</index_id>
<alias>App2 Alias</slot_alias>
</slot>
</product>
</slot_meta_data>
Here is my code
string newURL = "RESTURL";
HttpWebRequest request = WebRequest.Create(newURL) as HttpWebRequest;
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
StreamReader reader = new StreamReader(response.GetResponseStream());
XmlDocument xdoc = new XmlDocument();
xdoc.Load(response.GetResponseStream());
XmlNodeList list = xdoc.SelectNodes("/slot_meta_data[#*]");
foreach (XmlNode node in list)
{
XmlNode product = node.SelectSingleNode("product");
string name = product["name"].InnerText;
string id = product["id"].InnerText;
Console.WriteLine(name);
Console.WriteLine(id);
Console.ReadLine();
}
When I debug list, it has a count of 0.
Using xml linq
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication22
{
class Program
{
const string FILENAME = #"c:\TEMP\TEST.XML";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
var results = doc.Descendants("product").Select(x => new {
name = (string)x.Element("name"),
slot = x.Elements("slot").Select(y => new {
agent_id = (int)y.Element("agent_id"),
agent_name = (string)y.Element("agent_name"),
index_id = (int)y.Element("index_id"),
slot_alias = (string)y.Element("slot_alias")
}).FirstOrDefault()
}).ToList();
}
}
}

Categories