Get data from XML in simple way - c#

I am using the following code to get data from the OData XML and its works ,
but I am not sure that I fully understand it so maybe there is a way to write it in simple way?
what i need is to get the property value which is in the first loop value = 0001 and text = approve and in the
second value = 0002 text = reject
The code
XNamespace dns = "http://schemas.microsoft.com/ado/2007/08/dataservices";
if (response.StatusCode == HttpStatusCode.OK)
{
string decisionOptions = ReadResponse(response);
XDocument document = XDocument.Parse(decisionOptions);
foreach (XElement element in document.Element(dns + "DecisionOptions").Elements(dns + "element"))
{
PropertyKeyRef decisionOption = new PropertyKeyRef();
decisionOption.PropertyValue = element.Element(dns + "DecisionKey").Value;
decisionOption.PropertyName = element.Element(dns + "DecisionText").Value;
dat.Add(decisionOption);
}
}
the XML
<?xml version="1.0" encoding="utf-8" ?>
- <d:DecisionOptions xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
- <d:element m:type="TAS.DecisionOption">
<d:InstanceID>007</d:InstanceID>
<d:DecisionKey>0001</d:DecisionKey>
<d:DecisionText>Approve</d:DecisionText>
<d:CommentMandatory>false</d:CommentMandatory>
<d:Nature>POSITIVE</d:Nature>
</d:element>
- <d:element m:type="TAS.DecisionOption">
<d:InstanceID>007</d:InstanceID>
<d:DecisionKey>0002</d:DecisionKey>
<d:DecisionText>Reject</d:DecisionText>
<d:CommentMandatory>true</d:CommentMandatory>
<d:Nature>NEGATIVE</d:Nature>
</d:element>
</d:DecisionOptions>

here how can do it in simple way using LINQ
namespace ConsoleApplication7
{
class Program
{
static void Main(string[] args)
{
XDocument xdoc = XDocument.Load("test.xml");
XNamespace dns = "http://schemas.microsoft.com/ado/2007/08/dataservices";
//in xml every element should have it's namespace for this reason I have to concatenate namespace with the name of element
var elementsRes = xdoc.Root.Elements(dns+"element").Select((elt) => new PropertyKeyRef { PropertyName = elt.Element(dns+"DecisionKey").Value.ToString(),PropertyValue = elt.Element(dns+"DecisionText").Value.ToString() }).ToList();
foreach (var item in elementsRes)
{
//your code for the result
}
}
}
public class PropertyKeyRef
{
public string PropertyName
{ get; set; }
public string PropertyValue
{ get; set; }
}
}

You have already achieved it in simplest way. Little bit of LINQ might improve readability (get away with foreach loop) but it's just syntactic sugar of what you have written.
XNamespace dns = "http://schemas.microsoft.com/ado/2007/08/dataservices";
XDocument document = XDocument.Load("database.xml");
PropertyKeyRef decisionOption = new PropertyKeyRef();
decisionOption.PropertyValue = document.Descendants(dns + "DecisionKey")
.Select(node => node.Value).First();
decisionOption.PropertyName = document.Descendants(dns + "DecisionText")
.Select(node => node.Value).First();
dat.Add(decisionOption);

Related

How to get separate values from Xlement

This is a portion of XML I'm trying to parse
<BRTHDATES>
<BRTHDATE value="5/1/1963" code="B"/>
</BRTHDATES>
var birthdates = xmlDoc.XPathSelectElements("/INDV/PERSON/BRTHDATES").Elements().Where(e => e.Name == "BRTHDATE");
xe = birthdates.Elements().Where(e => e.Name == "BRTHDATE");
bbs = from b in birthdates
select new
{
Birthdays = b.FirstAttribute.Value,
Code = b?.Value
};
var status = birthdates.Elements().Where(e => e.Name.LocalName == "BRTHDATE").Single().Value;
When I try to get "Value" from the Element I get an empty string. I can't get anything for the "code" attribute.
It sure seems like this should be a lot easier...
You can try below code. I've already tested through a test project and got the require value.
string personBirthday = string.Empty;
string soapResult = #"<?xml version=""1.0"" encoding=""utf - 8"" ?><INDV> <PERSON> <BRTHDATES><BRTHDATE value = ""5/1/1963"" code = ""B"" /> </BRTHDATES></PERSON></INDV> ";
XmlDocument doc = new XmlDocument();
doc.Load(new StringReader(soapResult));
XmlNodeList person = doc.GetElementsByTagName("BRTHDATES");
if (person[0].ChildNodes.Count > 0)
{
foreach (XmlNode item in person[0].ChildNodes)
{
if (item.Name.Trim().Equals("BRTHDATE"))
{
personBirthday = !string.IsNullOrEmpty(item.Attributes[0].Value) ? item.Attributes[0].Value.Trim() : string.Empty;
}
}
}
Here is the solution
You can select specific Element from a Xml. Just try below sample code
XmlNodeList generalTabNodeList = xmlDocument.SelectNodes("/INDV/PERSON/BRTHDATES");
foreach (XmlNode node in generalTabNodeList)
{
if (node.ChildNodes.Count > 0)
{
string birthdate = !string.IsNullOrEmpty(node.ChildNodes[0].ToString()) ? node.ChildNodes[2].InnerText.ToString() : string.Empty;
}
}
I can't quite follow what you are trying to do, but, this should get you going:
For an XML file that looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<INDV>
<PERSON>
<BRTHDATES>
<BRTHDATE value="5/1/1963" code="B"/>
</BRTHDATES>
</PERSON>
</INDV>
(Note, this is an entire XML document - one that matches your code, not just the snippet you provided (that doesn't match your code))
This code will pick out the value and code attributes:
using (var xmlStream = new FileStream("Test.xml", FileMode.Open))
{
XDocument xmlDocument = XDocument.Load(xmlStream);
var birthDateElements = xmlDocument.XPathSelectElements("/INDV/PERSON/BRTHDATES/BRTHDATE");
var birthDateElement = birthDateElements.FirstOrDefault();
if (birthDateElement != null)
{
var attributes = birthDateElement.Attributes();
var valueAttribute = attributes.Where(a => a.Name == "value");
var codeAttribute = attributes.Where(a => a.Name == "code");
}
}
You can play around with this code to figure out what you want to do. Whatever you do, don't pick out attributes by position, pick them out by name.

Load repeated elements from an XML file

I am looking to load repeated elements from an XML file I have called initialInspections.xml. The problem is that the system needs to be dynamic and to allow as many different inspectionNotes to be added. I need to input all of them even though they have the same name.
If someone could please give me a method of doing this I would be extremely appreciative, since I have been searching for almost 3 hours now and I haven't found anything that works.
I need all off the data from within each inspectionNote node, and it will be put into an array of a structure called initialInspectionNotes.
Here is what I have up to now:
public int propertyID;
public string initialInspectorUsername;
public DateTime intialDateTime;
public struct initialInspectionNotes
{
public string locationWithinProperty;
public string locationExtraNote;
public string costCode;
public float estimatedTime;
}
private void finalInspection_Load(object sender, EventArgs e)
{
//Open the intialInspections xml file and load the values into the form
XmlDocument xdoc = new XmlDocument();
FileStream rFile = new FileStream(values.xmlInitialFileLocation, FileMode.Open);
xdoc.Load(rFile);
XmlNodeList list = xdoc.GetElementsByTagName("initialInspection");
for (int i = 0; i < list.Count; i++)
{
XmlElement initialInspection = (XmlElement)xdoc.GetElementsByTagName("initialInspection")[i];
XmlElement initialInspector = (XmlElement)xdoc.GetElementsByTagName("userInspection")[i];
XmlElement dateTime = (XmlElement)xdoc.GetElementsByTagName("dateTime")[i];
propertyID = int.Parse(initialInspection.GetAttribute("propertyID"));
initialInspectorUsername = initialInspector.InnerText;
intialDateTime = DateTime.Parse(dateTime.InnerText);
}
rFile.Close();
}
The XML looks like this:
<?xml version="1.0" standalone="yes"?>
<initialInspections>
<initialInspection propertyID="1">
<userInspection>defaultadmin</userInspection>
<dateTime>07/11/2015 17:15:20</dateTime>
<inspectionNote>
<location>Dining Room</location>
<locationNote>Remove whole carpet, leave underlay</locationNote>
<CostCode>L1</CostCode>
<estimatedTime>5</estimatedTime>
</inspectionNote>
<inspectionNote>
<location>Other - See Notes</location>
<locationNote>On the marked area with orange spray paint.</locationNote>
<CostCode>B1</CostCode>
<estimatedTime>12</estimatedTime>
</inspectionNote>
</initialInspection>
</initialInspections>
Any help would be much appreciated.
class Note
{
public string Location { get; set; }
public string LocationNote { get; set; }
public string CodeCost { get; set; }
public string EstimatedTime { get; set; }
}
var xml = XElement.Load(...your xml path here );
var data = xml.Descendants("initialInspection").Elements("inspectionNote").Select(n => new Note()
{
Location = n.Element("location").Value,
LocationNote = n.Element("locationNote").Value,
CodeCost = n.Element("CostCode").Value,
EstimatedTime = n.Element("estimatedTime").Value
}).ToList();
One possibility would be to use the LINQ2XML and the LINQ Descendants method to fetch all inspectionNotes at once:
var xml = XDocument.Load(fileLocation); // for example c:\temp\input.xml
// fetch all inspectionNotes
var inspectionNotes = xml.Root.Descendants("inspectionNote").ToList();
// TODO: error handling!
// map inspectionNote node to custom structure
var arrayOfNotes = inspectionNotes.Select (n => new initialInspectionNotes
{
costCode = n.Element("CostCode").Value,
estimatedTime = float.Parse(n.Element("estimatedTime").Value),
locationExtraNote = n.Element("locationNote").Value,
locationWithinProperty = n.Element("location").Value,
})
// and convert the result to array holding elements of the custom structure
.ToArray();
foreach (var note in arrayOfNotes)
{
Console.WriteLine(note.locationExtraNote);
}
The output is:
Remove whole carpet, leave underlay
On the marked area with orange spray paint.
Same logic applies if you want to read and map another XML nodes (f.e. initialInspection).
If you need to use XmlReader then use XPath in order to fetch the inner inspectionNote elements and the values of every inspectionNote element, using XmlNode.SelectSingleNode and XmlNode.SelectNodes:
//Open the intialInspections xml file and load the values into the form
XmlDocument xdoc = new XmlDocument();
FileStream rFile = new FileStream(values.xmlInitialFileLocation, FileMode.Open);
xdoc.Load(rFile);
XmlNodeList list = xdoc.GetElementsByTagName("initialInspection");
// create list of initialInspectionNotes in order to add as many nodes as needed
var notes = new List<initialInspectionNotes>();
// map data
for (int i = 0; i < list.Count; i++)
{
// read data
XmlElement initialInspection = (XmlElement)xdoc.GetElementsByTagName("initialInspection")[i];
XmlElement initialInspector = (XmlElement)xdoc.GetElementsByTagName("userInspection")[i];
XmlElement dateTime = (XmlElement)xdoc.GetElementsByTagName("dateTime")[i];
propertyID = int.Parse(initialInspection.GetAttribute("propertyID"));
initialInspectorUsername = initialInspector.InnerText;
intialDateTime = DateTime.Parse(dateTime.InnerText);
// fetch notes!
var inspectionNotes = initialInspection.SelectNodes("inspectionNote");
foreach (XmlNode inspectionNote in inspectionNotes)
{
// insert data into list
notes.Add(new initialInspectionNotes
{
locationExtraNote = inspectionNote.SelectSingleNode("locationNote").InnerText,
costCode = inspectionNote.SelectSingleNode("CostCode").InnerText,
locationWithinProperty = inspectionNote.SelectSingleNode("location").InnerText
});
}
}
// convert to array if needed
//var arrayOfNotes = notes.ToArray();
rFile.Close();
Regardless of how many inspectionNote elements the XML contains, the list resp. array will read them all.
class InitialInspectionNotes
{
public string Location { get; set; }
public string LocationNote { get; set; }
public string CodeCost { get; set; }
public string EstimatedTime { get; set; }
}
var xdoc = XDocument.Load("yourpath\filename.xml");
var dataXml = xdoc.Descendants("initialInspection").Elements("inspectionNote").Select(n => new InitialInspectionNotes()
{
Location = n.Element("location").Value,
LocationNote = n.Element("locationNote").Value,
CodeCost = n.Element("CostCode").Value,
EstimatedTime = n.Element("estimatedTime").Value
}).ToList();
var xmlList = new List<object>();
for (int i = 0; i < dataXml.Count; i++)
{
xmlList.Add(dataXml[i]);
}
Despite all the answers above might have worked, I have however found it quite complicated for reading just elements. I found a simpler solution which I would like to share for future audience in this case.
Supposing you have read the document stream into XmlDocument object named as document.
var dataNodes = document.GetElementsByTagName("Data");
var toList = dataNodes.OfType<XmlElement>().ToList();
In my case, Data node was not being called repeatedly. Hence this works, now I was able to append multiple nodes with the same name.

XML to String List

I have some code that I need to put into a string list in C# and I am reading this code from an XML files and the layout of it is something like below...
<?xml version="1.0"?>
<accountlist>
<main>
<account id="1" special_id="4923959">
<username>Adam</username>
<motto>Hello Everyone>
<money>1004</money>
<friends>394</friends>
<rareid>9</rareid>
<mission>10</mission>
</account>
</main>
</accountlist>
How can I put each account tag into a string list? from the first < account > to the < / account > tag?
Please do NOT tell me to go to the link below as it does NOT work!!
How to read a XML file and write into List<>?
So far I have tried the below code, and the string list just stays empty
XDocument doc = XDocument.Parse(this._accountsFile);
List<string> list = doc.Root.Elements("account")
.Select(element => element.Value)
.ToList();
this._accounts = list;
You'll have to use Descendants instead of Elements:
List<string> list = doc.Root.Descendants("account").Descendants()
.Select(element => element.Value)
.ToList();
Elements only returns child elements of the element (in case of the root element this means <main>).
Descendants returns the entire tree inside the element.
Also: You'll have to fix the tag <motto>Hello Everyone> to <motto>Hello Everyone</motto>
This will work on your example (but you need to close this tag <motto>Hello Everyone>
public List<string> GetAccountsAsXmlList(string filePath)
{
XmlDocument x = new XmlDocument();
x.Load(filePath);
List<string> result = new List<string>();
XmlNode currentNode;
foreach (var accountNode in x.LastChild.FirstChild.ChildNodes)
{
currentNode = accountNode as XmlNode;
result.Add(currentNode.InnerXml);
}
return result;
}
EDIT as an answer to your question:
Is there a way I can get the id and specal_id in a seperate string?
you can use currentNode.Attributes["YourAttributeName"].Value, to get the values.
assume you have class Account :
class Account
{
public string accountXml { get; set; }
public string Id { get; set; }
public string Special_id { get; set; }
}
Then :
public List<Account> GetAccountsAsXmlList(string filePath)
{
XmlDocument x = new XmlDocument();
x.Load(filePath);
List<Account> result = new List<Account>();
XmlNode currentNode;
foreach (var accountNode in x.LastChild.FirstChild.ChildNodes)
{
currentNode = accountNode as XmlNode;
result.Add(new Account
{
accountXml = currentNode.InnerXml,
Id = currentNode.Attributes["id"].Value,
Special_id = currentNode.Attributes["special_id"].Value,
});
}
return result;
}
Use XPath to get the account element first:
using System.Xml.XPath;
XDocument doc = XDocument.Parse(xml);
foreach(var account in doc.XPathSelectElements("accountlist/main/account")){
List<string> list = account.Descendants()
.Select(element => element.Value)
.ToList();
}
Try this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication37
{
class Program
{
static void Main(string[] args)
{
string input =
"<?xml version=\"1.0\"?>" +
"<accountlist>" +
"<main>" +
"<account id=\"1\" special_id=\"4923959\">" +
"<username>Adam</username>" +
"<motto>" +
"Hello Everyone>" +
"<money>1004</money>" +
"<friends>394</friends>" +
"<rareid>9</rareid>" +
"<mission>10</mission>" +
"</motto>" +
"</account>" +
"</main>" +
"</accountlist>";
XDocument doc = XDocument.Parse(input);
var results = doc.Descendants("accountlist").Select(x => new {
id = x.Element("main").Element("account").Attribute("id").Value,
special_id = x.Element("main").Element("account").Attribute("special_id").Value,
username = x.Element("main").Element("account").Element("username").Value,
motto = x.Element("main").Element("account").Element("motto").FirstNode.ToString(),
money = x.Element("main").Element("account").Element("motto").Element("money").Value,
friends = x.Element("main").Element("account").Element("motto").Element("friends").Value,
rareid = x.Element("main").Element("account").Element("motto").Element("rareid").Value,
mission = x.Element("main").Element("account").Element("motto").Element("mission").Value,
}).ToList();
}
}
}

How can i update xml file in c#

I write console application program
this is my xml file:
<?xml version="1.0" encoding="utf-8" ?>
<Settings>
<AsteriskHost type="string">172.16.18.14</AsteriskHost>
</Settings>
I run this code
public void Set(List<AcmSettings> acmSettings)
{
XElement xelement = XElement.Load("Settings.xml");
IEnumerable<XElement> settings = xelement.Elements();
foreach (var item in acmSettings)
{
settings.FirstOrDefault(x => x.Name == item.Name).SetValue("treeee");
}
xelement.Save("Settings.xml");
}
this my test:
[Test]
public void SetShouldUpdateValue()
{
var settingsManager = new SettingsManager();
const string newIp = "165.166.167.167";
const string elemntName = "AsteriskHost";
var acmSetting = new List<AcmSettings> { new AcmSettings { Name = elemntName, Value = newIp } };
settingsManager.Set(acmSetting);
var setting = settingsManager.Get(x => x.Name == elemntName).FirstOrDefault();
Assert.IsTrue(setting != null);
Assert.IsTrue(setting.Value== newIp);
}
I don't have any error but my new value not save in file.
How can I update xml node in c#
I tried your Set method, and it runs ok for me. I did have to tweak your current implementation by changing just one line:
// settings.FirstOrDefault(x => x.Name == item.Name).SetValue("treeee");
settings.FirstOrDefault(x => x.Name == item.Name).SetValue(item.Value);
Perhaps the problem is with your Get method. Here is a quick (not production quality) Get implementation. Using this implementation, your unit test runs successfully.
// note - just a string (name) passed in
public XElement Get(string name)
{
XElement xelement = XElement.Load("Settings.xml");
IEnumerable<XElement> settings = xelement.Elements();
return settings.FirstOrDefault(x => x.Name == name);
}
The other possibility is that, as suggested in the comments above, is that you are looking at your project XML file, and not looking at the output XML file.
Try like this
XmlDocument xmlDom = new XmlDocument();
xmlDom.Load("YourXMLFILEPATH.xml");
XmlNode newXMLNode = xmlDom.SelectSingleNode("/Settings/AsteriskHost");
newXMLNode.InnerText = YourValue;
xmlDom.Save("YourXMLFILEPATH.xml");
Console.WriteLine(xmlDom);
Have you tried this ?
You can modify your set method like this.
public void Set(List<AcmSettings> acmSettings)
{
XElement xelement = XElement.Load("Settings.xml");
IEnumerable<XElement> settings = xelement.Elements();
foreach (var item in acmSettings)
{
xelement.Descendants(item.Name).FirstOrDefault().Value = item.Value;
}
xelement.Save("Settings.xml");
}

monodevelop parse soap response

been reading this and others forums for hours and days now and can't find a solution for my soap response. Been trying all kinds of answers here, but can't parse my response :(
my response :
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<getLocationsResponse xmlns="http://getlocations.ws.hymedis.net">
<locs>
<loc>
<name>Zeebrugge Wielingen Zand</name>
<abbr>ZWZ</abbr>
<RDX>1435.8</RDX>
<RDY>378678.6</RDY>
<params>
<param>GHs</param>
<param>SS10</param>
</params>
</loc>
</locs>
</getLocationsResponse>
</soapenv:Body>
</soapenv:Envelope>
My c# code so far (param soapresponse is the whole soapresponse in string format) my response is correct, so the full xml soap response, but can't parse it good
public void readXml(string soapresponse){
XmlDocument xmlresponse = new XmlDocument();
xmlresponse.LoadXml(soapresponse);
XmlNamespaceManager nsmanager = new XmlNamespaceManager(xmlresponse.NameTable);
nsmanager.AddNamespace ("soapenv", "http://schemas.xmlsoap.org/soap/envelope/");
XmlNodeList nodes = xmlresponse.SelectNodes("/soapenv:Envelope/soapenv:Body/getLocationsResponse/locs/loc", nsmanager);
List<Locatie> locatielijst = new List<Locatie>();
// loop
foreach(XmlNode node in nodes){
string loc_naam = node["name"].InnerText;
string loc_code = node["abbr"].InnerText;
...
Locatie locatie = new Locatie();
locatie.loc_naam = loc_naam;
locatie.loc_code = loc_code;
...
locatielijst.Add (locatie);
}
Console.WriteLine(locatielijst.Count.ToString());
foreach(Locatie loc in locatielijst){
Console.WriteLine (loc.loc_code);
}
}
but every time my list.count returns 0 -> so no data in them.. plz help me out!
The following code might work.
public class MainClass
{
public static void Main(string[] args)
{
var response = new FileStream("Response.xml", FileMode.Open);
XDocument doc = XDocument.Load(response);
XNamespace xmlns = "http://getlocations.ws.hymedis.net";
var nodes = doc.Descendants(xmlns + "locs")
.Elements(xmlns + "loc");
var list = new List();
foreach (var node in nodes)
{
list.Add(new Location {
Name = node.Element(xmlns + "name").Value,
Code = node.Element(xmlns + "abbr").Value
});
}
foreach (var item in list) {
Console.WriteLine(item.Code);
}
}
public class Location
{
public string Code { get; set; }
public string Name { get; set; }
}
}
I don't have much experience with mono but .net made it very easy to consume WCF SOAP services.
This article explains how to generate the proxy classes for a WCF service:
http://johnwsaunders3.wordpress.com/2009/05/17/how-to-consume-a-web-service/
I hope this helps.
Regards,
Wouter Willaert

Categories

Resources