XDocument does not load Xml string properly - c#

I'm trying to do the following: load an Xml string into a XDocument object, but when I try to access elements through Descendants method it return nothing when I tried to see the value of inner elements in Visual Studio it does not recognize it as Xml so what is the problem here?
string xml = #"<ArrayOfKeyValueOfstringint xmlns=""http://schemas.microsoft.com/2003/10/Serialization/Arrays"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance"">
<KeyValueOfstringint>
<Key>crscmprsn_ttlprt1</Key>
<Value>1</Value>
</KeyValueOfstringint>
<KeyValueOfstringint>
<Key>ptntmntrfrm_ttlprt1</Key>
<Value>1</Value>
</KeyValueOfstringint>
</ArrayOfKeyValueOfstringint>";
var xdoc = XDocument.Parse(xml);
IEnumerable<XElement> elements = xdoc.Descendants("KeyValueOfstringint");
var lst = new List<KeyValuePair<string,int>>();
foreach (var item in elements)
{
var k = item.Element("Key").Value;
int v = int.Parse(item.Element("Value").Value);
var kvp = new KeyValuePair<string,int>(k,v);
lst.Add(kvp);
}

You need to specify namespace to get your elements:
var ns = "http://schemas.microsoft.com/2003/10/Serialization/Arrays";
var elements = xdoc.Descendants(ns + "KeyValueOfstringint");
For more information about xml namespaces take a look at: Working with XML Namespaces

Related

How to seperate strings from a serialized XML node

I have an serialized XML file. This shows the relevant part:
I am reading this XML file with this (code snippet):
temp = Path.GetFileNameWithoutExtension(s);
var document = new XmlDocument();
document.Load(s);
var root = document.DocumentElement;
var node = root["ScenarioDescription"];
var text = node?.InnerText;
var ArmyNode = root["ArmyFiles"];
var ArmyText = ArmyNode?.InnerText;
However, ArmyText returns the concatenation of all three strings that make up the ArmyFiles node. I need them as three separate strings. How can I do this?
This code works to read all the strings in the node and place them into a list:
foreach (XmlElement A in ArmyNode)
{
var ArmyTemp = A.InnerText;
ArmyList.Add(ArmyTemp);
}
var ArmyText = ArmyNode?.InnerText;

LINQ xml finding nodes returns null

I try to parse an xml file with XDocument class, with criteria that if the child node matches a given string, its parent node is selected.
<SalesQuotes xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://api.some.com/version/1">
<Pagination>
<NumberOfItems>2380</NumberOfItems>
<PageSize>200</PageSize>
<PageNumber>1</PageNumber>
<NumberOfPages>12</NumberOfPages>
</Pagination>
<SalesQuote>
<Guid>825634b9-28f5-4aa7-98e7-5e4a4ed6bc6a</Guid>
<LastModifiedOn>2018-01-09T12:23:56.6133445</LastModifiedOn>
<Comments>Please note:
installation is not included in this quote
</Comments>
</SalesQuote>
</SalesQuotes>
I tried using
var contents = File.ReadAllText(path: "test1.xml");
var doc = XDocument.Parse(contents);
var root = doc.Root;
var sq = root.Elements("SalesQuote");//return null
var theQuote = root.Elements("SalesQuote").Where(el => el.Element("Guid").Value == "825634b9-28f5-4aa7-98e7-5e4a4ed6bc6a");//return null
var theAlternativeQuote =
from el in doc.Descendants("SalesQuote").Elements("Guid")
where el.Value == "825634b9-28f5-4aa7-98e7-5e4a4ed6bc6a"
select el;//return null
I can't seem to find what's wrong.
Any help is much appreciated! Thanks.
You ignored the namespace bro.
Do remove the xmlns attribute in your XML or try this:
var contents = File.ReadAllText("XMLFile1.xml");
var doc = XDocument.Parse(contents);
var root = doc.Root;
XNamespace ns = "http://api.some.com/version/1";
var sq = root.Descendants(ns + "SalesQuotes"); //return null
var theQuote = root.Elements(ns + "SalesQuote")
.Where(el => el.Element(ns + "Guid").Value == "825634b9-28f5-4aa7-98e7-5e4a4ed6bc6a"); //return null
var theAlternativeQuote =
from el in doc.Descendants(ns + "SalesQuote").Elements(ns + "Guid")
where el.Value == "825634b9-28f5-4aa7-98e7-5e4a4ed6bc6a"
select el; //return null
If you are not too concerned about keeping your current implementation, you could consider using a Typed DataSet and load your XML into fully typed, structured objects.
Querying those objects with Linq will be more straight forward than what I see in your current implementation.
You might also find this useful:
SO Question: Deserialize XML Document to Objects
yap, you're missing the namespace that you can grab with document.Root.GetDefaultNamespace()
// Load
var document = XDocument.Parse(xml);
var xmlns = document.Root.GetDefaultNamespace();
// Find
var query = from element in document
.Descendants(xmlns + "SalesQuote")
.Elements(xmlns + "Guid")
where element.Value == "825634b9-28f5-4aa7-98e7-5e4a4ed6bc6a"
select element;

C# split xml innertext or parse innerxml

I have an XML file with a structure similar to this
<entry name="something">
<members>
<member>aaa</member>
<member>bbb</member>
</members>
</entry>
<entry name="something_else">
<members>
<member>ccc</member>
<member>ddd</member>
</members>
</entry>
I need to be able to get the values out of each of the member nodes to store in a datatable. if i use the innertext property, it concatenates the values (aaabbb). there is nothing discernible to split the string on. I can also use the inner XML but then i just get a string with the XML structure (aaa bbb<\member>)
What is the best way to get each value out of the XML elements and store it in a string array?
here is what I have been trying.
foreach (XmlNode grpNode in GrpList)
{
subNode = grpNode.Attributes["name"];
if (subNode != null)
{
Obj = grpNode.Attributes["name"].Value;
}
subNode = grpNode["members"];
if (subNode != null)
{
string innerXml = string.Empty;
innerXml = grpNode["members"].InnerXml.ToString();
string[] tempArrary = innerXml.Split(new char[] {'>', '<'});
}
}
You can use Xpath to iterate through Entry nodes and get the members within it like this
string xml = "<root><entry name='something'>" +
"<members>" +
"<member>aaa</member>" +
"<member>bbb</member>" +
"</members>" +
"</entry>" +
"<entry name='something_else'>" +
"<members>" +
"<member>ccc</member>" +
"<member>ddd</member>" +
"</members>" +
"</entry></root>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
var memsList = doc.SelectNodes("//entry");
foreach (XmlNode a in memsList)
{
Console.WriteLine(a.Attributes["name"].Value);
var memList = a.SelectNodes("members/member");
foreach(XmlNode x in memList)
Console.WriteLine(x.InnerText);
}
You need to iterate the child elements within members, so something like:
foreach (var node in grpNode["members"].ChildNodes)
{
var value = node.InnerText;
}
That said, you would be better off using LINQ to XML unless you have some specific reason to use XmlDocument. This gives you much more expressive code, for example:
var doc = XDocument.Parse(xml);
var something = doc.Descendants("entry")
.Where(e => (string)e.Attribute("name") == "something")
.Single();
var somethingMembers = something.Descendants("member")
.Select(e => e.Value)
.ToArray();
This should do the trick:
XDocument xdoc = XDocument.Load(#"Path/to/file");
var result = xdoc.Descendants("member").Select (x => x.Value).ToArray();
Result:
Demo Code
the xml you've provided isn't valid. But assuming you just want the inner text of all member nodes into a string array, I'd just use Linq-To-Xml (XDocument):
var results = XDocument.Parse(xmlString)
.Descendants("member")
.Select(m => m.Value)
.ToArray();
Even though you're using the old XmlDocument API, by throwing in an .OfType<XmlNode>() you can convert an XmlNodeList to a generic enumerable and thereby mix in some linq and lambda syntax, for instance:
var tempArrary = subNode.SelectNodes("member").OfType<XmlNode>().Select(n => n.InnerText).ToArray();

Parse XML using XDocument in Windows Phone 8

Can any one tell me how to parse XML which is in this format using XDocument in Windows phone 8
<search total="" totalpages="">
<domain>
<makes filter="">
<make cnt="374" image="abc.png">One</make>
<make cnt="588" image="bca">Two</make>
<make cnt="105" image="tley.png">Three</make>
<make cnt="458" image="mw.png">Four</make>
</makes>
</domain>
</search>
Right now i am using this code but unable to get the data out. I need image and name from this XML.
XDocument xdoc = XDocument.Parse(flickRes);
var rootCategory = xdoc.Root.Elements("makes");
List<string> list = new List<string>();
foreach (XElement book in rootCategory.Elements("make"))
{
string id = (string)book.Attribute("image");
string name = (string)book;
Debug.WriteLine(id);
//list.Add(data);
}
Thanks In Advance
Elements returns only direct children of current element (with matching name, when provided). Because <makes> is not direct child of root element, xdoc.Root.Elements("makes") will return empty collection.
Add another Element("domain") call on xdoc.Root before calling Element("makes").
XDocument xdoc = XDocument.Parse(flickRes);
var rootCategory = xdoc.Root.Element("domain").Element("makes");
List<string> list = new List<string>();
foreach (XElement book in rootCategory.Elements("make"))
{
string id = (string)book.Attribute("image");
string name = (string)book;
Debug.WriteLine(id);
//list.Add(data);
}

parsing a xml file which contains more than one keyvalues using c#

I have file format
<?xml version='1.0' encoding='us-ascii'?>
<root>
<file id="001">
<filename>ABC.wav</filename>
<value>0.18</value>
</file>
<file id="002">
<filename>EFG.wav</filename>
<value>0.05</value>
<value>0.14</value>
</file>
</root>
I want to parse that USING C#
doc.Load(confidencethresholdFilePath+"\\model.xml");
XmlNodeList nodes = doc.DocumentElement.SelectNodes("/root/file");
List<Result> results = new List<Result>();
foreach (XmlNode node in nodes)
{
Result result = new Result();
result.ASfilename= node.SelectSingleNode("filename").InnerText;
result.resultedSeconds = node.SelectSingleNode("value").InnerText;
results.Add(result);
}
It gives result but misses the second record's second value.How do i get all results without fail.
How about using LINQ to XML?
var xDoc = XDocument.Load("Input.xml");
var results =
xDoc.Root
.Elements("file")
.Select(f => new
{
FileName = (string)f.Element("filename"),
Values = f.Elements("value").Select(v => (string)v).ToList()
})
.ToList();
results will be a list of anonymous type instances with two properties: FileName:string and Values:List<string>. You can easily change it to return List<Record> instead, just change f => new to f => new Record and update properties info.
As you can see, it's much easier to get XML content using LINQ to XML than using old-style XmlSomething classes.
If you want a separate Result for each value and using your non-Linq style, you could change the initial selection. The file name selection will then need to change appropriately.
doc.Load(confidencethresholdFilePath+"\\model.xml");
XmlNodeList nodes = doc.DocumentElement.SelectNodes("/root/file/value");
List<Result> results = new List<Result>();
foreach (XmlNode node in nodes)
{
Result result = new Result();
result.ASfilename= node.SelectSingleNode("../filename").InnerText;
result.resultedSeconds = node.SelectSingleNode("value").InnerText;
results.Add(result);
}

Categories