Deserialize an xml file or parse using linq to xml - c#

Simplified XML file I need to decode:
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:deliverylistResponse xmlns:ns2="http://tdriverap3.wsbeans.iseries/">
<return>
<COUNT>3</COUNT>
<DELIVERIES>
<ADD1>1300 address 1</ADD1>
<CITY>NICE CITY</CITY>
<ZIP>85705</ZIP>
</DELIVERIES>
<DELIVERIES>
<ADD1>40 S PINAL PKWY AVE</ADD1>
<CITY>FLORENCE</CITY>
<ZIP>85132</ZIP>
</DELIVERIES>
<DELIVERIES>
<ADD1>1825 EAST MAIN</ADD1>
<CITY>CHANDLER</CITY>
<ZIP>85286</ZIP>
</DELIVERIES>
<ERRORCODE/>
<RUNDATE>09/26/2018</RUNDATE>
</return>
</ns2:deliverylistResponse>
</soap:Body>
</soap:Envelope>
I am using the following to try and decode each of the individual addresses in the code.
I cannot figure out how to access them.
XElement xelement = XElement.Load(#"e:\test\X2.xml");
IEnumerable<XElement> addresses = xelement.Elements();
foreach (var address in addresses)
{
Console.WriteLine(address);
Console.WriteLine(address.Element("CITY").Value);
}
The first writeline works (it outputs the entire XML tree), the second says "System.Xml.Linq.XContainer.Element(...) returned null" - I have tried using DELIVERIES, COUNT, Body etc...
Obviously I am not telling it correctly how to traverse the structure, but I do not know how to go any further with it..
UPDATE: Thanks to some help I have figured out how to do it using Linq.
I would still like to be able to deserialize it if anybody has a pointer.
I followed several tutorials, but the multiple levels of this XML seems to be throwing me off.
I have created a class to hold the data but that is as far as my success with that path has gone.
Thank you,
Joe

Thank you Crowcoder -- this is what I wound up with, which will work.
The real XML file however does have about 60 fields so this is not as good as using a deserialize routine but I can at least move forward with the project.
XElement xelement = XElement.Load(#"e:\test\x2.xml");
IEnumerable<XElement> textSegs =
from seg in xelement.Descendants("DELIVERIES")
select seg;
foreach (var address in textSegs)
{
Console.WriteLine(address.Element("ADD1").Value);
Console.WriteLine(address.Element("CITY").Value);
Console.WriteLine(address.Element("ZIP").Value);
}
Console.ReadKey();

Related

How to get list of values when XML contains many namespaces

I have following XML:
<?xml version="1.0" encoding="utf-16"?>
<cincinnati xmlns="http://www.sesame-street.com/abc/def/1">
<cincinnatiChild xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<ElementValue xmlns:a="http://schemas.data.org/2004/07/sesame-street.abc.def.ghi">
<a:someField>false</a:someField>
<a:data xmlns:b="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<b:KeyValueThing>
<b:Key>key1</b:Key>
<b:Value i:type="a:ArrayOfPeople">
<a:Person>
<a:firstField>
</a:firstField>
<a:dictionary>
<b:KeyValueThing>
<b:Key>ID</b:Key>
<b:Value i:type="c:long" xmlns:c="http://www.w3.org/2001/XMLSchema">000101</b:Value>
</b:KeyValueThing>
<b:KeyValueThing>
<b:Key>Name</b:Key>
<b:Value i:type="c:string" xmlns:c="http://www.w3.org/2001/XMLSchema">John</b:Value>
</b:KeyValueThing>
</a:dictionary>
</a:Person>
<a:Person>
...
<b:Value i:type="c:long" xmlns:c="http://www.w3.org/2001/XMLSchema">000102</b:Value>
...
</a:Person>
</b:Value>
</b:KeyValueThing>
</a:data>
</ElementValue>
</cincinnatiChild>
</cincinnati>
I need to get a list if ID values, e.g. 000101, 000102....
I think using XPath makes sense here but the multitude of namespaces makes it confusing (so a simple XmlNamespaceManager won't do).
Basically I need something like this (this syntax is of course not correct):
XmlDocument doc = // Load the xml
doc.DocumentElement.SelectSingleNode("/cincinati/cincinnatiChild/ElementValue/a:data/b:KeyValueThing/b:Value/a:Person/a:dictionary[b:KeyValueThing/b:Key='ID']");
also when I do doc.DocumentElement.SelectSingleNode("/cincinnati") or doc.DocumentElement.SelectSingleNode("/cincinnatiChild") I get null.
Since I'm unsure how to piece together al the helpfull advice from the comments I would like to see a working c# code line, either XmlDocument or XDocument are OK.
I also tries this before the SelectSingleNode:
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("a", "http://schemas.data.org/2004/07/sesame-street.abc.def.ghi");
nsmgr.AddNamespace("b", "http://schemas.microsoft.com/2003/10/Serialization/Arrays");
nsmgr.AddNamespace("c", "http://www.w3.org/2001/XMLSchema");
nsmgr.AddNamespace("i", "http://www.w3.org/2001/XMLSchema-instance");
nsmgr.AddNamespace("d", "http://www.sesame-street.com/abc/def/1");
You could bypass the namespace issues using the local-name()-function.
i.e.: in stead of b:KeyValueThing use *[local-name()='KeyValueThing']
a simple global XPath could look like this:
//*[local-name()='KeyValueThing'][*[local-name()='Key' and text()='ID' ]]/*[local-name()='Value']/text()
If you want to be more precise and speed up the XPath it would look like this:
/*[local-name()='cincinnati']/*[local-name()='cincinnatiChild']/*[local-name()='ElementValue']/*[local-name()='data']/*[local-name()='KeyValueThing']/*[local-name()='Value']/*[local-name()='Person']/*[local-name()='dictionary']/*[local-name()='KeyValueThing'][*[local-name()='Key' and text()='ID' ]]/*[local-name()='Value']/text()

Checking in xml if node exists c#

I send some request and i get xml response sometimes i get
<?xml version="1.0" encoding="UTF-8"?>
<debt-response>
<status>0</status>
<name>ნ.ს.</name>
<schedules>
<schedule>07.07.2017 1171.8000 GEL 1</schedule>
<schedule>07.08.2017 1171.8000 GEL 1</schedule>
<schedule>07.09.2017 1171.8000 GEL 1</schedule>
</schedules>
</debt-response>
and sometimes i get
<?xml version="1.0" encoding="UTF-8"?>
<debt-response>
<status>0</status>
<name>ნ.ბ.</name>
<schedules>
<schedule>06.07.2018 1.5 GEL 1</schedule>
<debt>15.06.2018 0.97</debt>
</schedules>
</debt-response>
I am using var acc_numArray = xmlDoc.SelectNodes("/debt-response/schedules/debt"); but if no such element exists it goes in exception.
I want to get that debt if such node exists any solution ?
You could try
var debt = XDocument.Load("path to your xml").Descendants("debt").FirstOrDefault()?.Value;
which gets the first debt element and returns its value.
If you have more than one debt, the following code saves the element values in a list:
var debt = XDocument.Load("path to your xml").Descendants("debt").Select(d => d.Value).ToList();
If you are reading the xml from a stream, use XDocument.Parse("your string") instead of Load().
Note: you will need the System.Xml.Linq namespace.
Without seeing your code, I can only guess what you're doing - but one thing is certain, this line will not throw an exception if no nodes can be located by the specified XPath:
var acc_numArray = xmlDoc.SelectNodes("/debt-response/schedules/debt");
Instead, it will return an XmlNodeList with a count of zero.
I am assuming your exception is occurring when you try and access the nodelist as if it had items in it - but simply check the count and only access it if it is non-zero:
var acc_numArray = xmlDocument.SelectNodes("/debt-response/schedules/debt");
if (acc_numArray.Count > 0)
{
// Do stuff here
}
If you put an example of your actual code into the question it will be a lot easier to help you.

Lost prefix's definitions after deserialization of WCF message

I develop WCF-client. My client should validate incoming messages.
One of the messages has the following structure:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SOAP-ENV:Header>...</SOAP-ENV:Header>
<SOAP-ENV:Body>
<OpDescriptionResponse>
<Field Name="DateTime" Type="xsd:dateTime">
</OpDescriptionResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
In this case the client should validate: the field "DateTime" has type "dateTime" from namespace "http://www.w3.org/2001/XMLSchema".
This response is deserialized in structure containing array of XmlElement.
But I have an issue: after message is deserialized and I received corresponding variable, containing all Field nodes I can't determine value of prefix "xsd", i.e. if I take any elementof type XMLElement corresponding to Field node in reply and call element.GetNamespaceOfPrefix("xsd") I get empty string as result.
How can I get prefix's definitions are saved after deserialization?
Help me please to overcome this issue.
In order to influence the namespace/prefix, you need to use XmlSerializerNamespaces.
The following code provides a rough reference:
XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
namespaces.Add("prefixHere", "http://namespace.here/");
XmlSerializer tempSerializer = new XmlSerializer(messageObject.GetType());
tempSerializer.Serialize(Console.Out, messageObject, namespaces);
Regards,

Pivotviewer's .cxml parsing

I'm trying to do very simple operations on a .cxml file. As you know it's basically an .xml file. This is a sample file I created to test the application:
<?xml version="1.0" encoding="utf-8"?>
<Collection xmlns:p="http://schemas.microsoft.com/livelabs/pivot/collection/2009" SchemaVersion="1.0" Name="Actresses" xmlns="http://schemas.microsoft.com/collection/metadata/2009">
<FacetCategories>
<FacetCategory Name="Nationality" Type="LongString" p:IsFilterVisible="true" p:IsWordWheelVisible="true" p:IsMetaDataVisible="true" />
</FacetCategories>
<!-- Other entries-->
<Items ImgBase="Actresses_files\go144bwo.0ao.xml" HrefBase="http://www.imdb.com/name/">
<Item Id="2" Img="#2" Name="Anna Karina" Href="nm0439344/">
<Description> She is a nice girl</Description>
<Facets>
<Facet Name="Nationality">
<LongString Value="Danish" />
</Facet>
</Facets>
</Item>
</Items>
<!-- Other entries-->
</Collection>
I can't get any functioning simple code like:
XDocument document = XDocument.Parse(e.Result);
foreach (XElement x in document.Descendants("Item"))
{
...
}
The test on a generic xml is working. The cxml file is correctly loaded in document.
While watching the expression:
document.Descendants("Item"), results
the answer is:
Empty "Enumeration yielded no results" string
Any hint on what can be the error? I've also add a quick look to get Descendants of Facet, Facets, etc., but there are no results in the enumeration. This obviously doesn't happen with a generic xml file I used for testing. It's a problem I have with .cxml.
Basically your XML defines a default namespace with the xmlns="http://schemas.microsoft.com/collection/metadata/2009" attribute:
That means you need to fully qualify your Descendants query e.g.:
XDocument document = XDocument.Parse(e.Result);
foreach (XElement x in document.Descendants("{http://schemas.microsoft.com/collection/metadata/2009}Item"))
{
...
}
If you remove the default namespace from the XML your code actually works as-is, but that is not the aim of the exercise.
See Metadata.CXML project under http://github.com/Zoomicon/Metadata.CXML sourcecode for LINQ-based parsing of CXML files.
Also see ClipFlair.Metadata project at http://github.com/Zoomicon/ClipFlair.Metadata for parsing one's CXML custom facets too
BTW, at http://ClipFlair.codeplex.com can checkout the ClipFlair.Gallery project for how to author ASP.net web-based forms to edit metadata fragments (parts of CXML files) and merge them together in a single one (that you then convert periodically to DeepZoom CXML with PAuthor tool from http://pauthor.codeplex.com).
If anyone is interested in doing nesting (hierarchy) of CXML collections see
http://github.com/Zoomicon/Trafilm.Metadata
and
http://github.com/Zoomicon/Trafilm.Gallery

How to parse Soap XML in Windows Phone 7

I have a XML Like Below, But i am not able to parse it. Please help me to parse the below XML.
<?xml version="1.0" encoding="utf-8"?><soap:Envelope
xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body>
<GetResponse xmlns="http://tempuri.org/"><GetResult>
<diffgr:diffgram>
<NewDataSet>
<Table>
<a>hi1</a>
<b>hi2</b>
</Table>
<Table>
<a>hi3</a>
<b>hi4</b>
</Table>
</NewDataSet>
</diffgr:diffgram>
</GetResponse></GetResult>
</soap:Body>
</soap:Envelope>
Here i want the results of the Table (i.e a,b ) tag. I tried using Linq but i am not able parse it. i tried the code some thing like this:
//XML will be there in response string
String response = e.response;
public static String myNamespace = "http://tempuri.org/";
XDocument reader = XDocument.Parse(response);
var results = from result in reader.Descendants(XName.Get("GetResponse", myNamespace))
select result.Element("GetResult").
But this code is returning null.
Thanks In advance.
In you c# project, you can import a Web Reference and make that point to the web service provider you are using. This reference will create an encapsulation class which will abstract all the SOAP protocol to you.
See the MSDN link for more details: http://msdn.microsoft.com/en-us/library/d9w023sx%28VS.71%29.aspx

Categories

Resources