Parsing SOAP XML with XDocument - c#

I work with legacy system (not my design) and it have some data persisted in db as serialized xml (SOAP).
XML was created with SoapFormatter.
SoapFormatter formatter = new SoapFormatter();
formatter.Serialize(stream, o);
I can't simply deserialize from SOAP because of versioning problem. Model from which data were created have changed and deserialization of persisted data (in xml) is not possible. So I'm trying to figure out how to manually "deserialize" old SOAP to existing model.
I can load it into XDocument and then extract node values with LINQ. But I have problem with Guid values. They are stored in in SOAP XML like this:
<someId xsi:type="a2:Guid" xmlns:a2="http://schemas.microsoft.com/clr/ns/System">
<_a>1396006029</_a>
<_b>2720</_b>
<_c>20328</_c>
<_d>162</_d>
<_e>217</_e>
<_f>181</_f>
<_g>57</_g>
<_h>113</_h>
<_i>92</_i>
<_j>64</_j>
<_k>35</_k>
</someId>
Is there any way to do it painless?
I can read them one by one like this:
var someId = xdoc.Descendants(ns + "root").Elements("someId").Elements("_a").Value;
and try to parse to Guid but it doesn't look nice.
Thanks,
Mike

I added <Root xmlns:xsi="abc"> to xml because the xsi namespace wan't defined.
Try code below :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication28
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
Dictionary<string, int> dict = new Dictionary<string, int>();
XDocument doc = XDocument.Load(FILENAME);
XElement someId = doc.Descendants("someId").FirstOrDefault();
dict = someId.Elements().GroupBy(x => x.Name.LocalName, y => (int)y)
.ToDictionary(x => x.Key, y => y.FirstOrDefault());
}
}
}

Related

Get Each Value on an XML Node

I have an XML that looks like this:
<HiddenTopicsValues TopicCodes="TopicValues">
<Topic>
<Code>topic_aboutme</Code>
<Value>1</Value>
</Topic>
<Topic>
<Code>topic_aboutyou</Code>
<Value>1</Value>
</HiddenTopicsValues>
My goal is to create a Dictionary that lets the <Code> act as the Key, and <Value> as the Value (of the Dictionary). I declared the dictionary as shown below:
Dictionary<string,int> dictionary_topics = new Dictionary<string,int>();
And used a for loop to iterate all the values in the XML:
// Load XML Document
XmlDocument xmlTopics = new XmlDocument();
xmlTopics.Load(path);
// Get All Hidden Topics
XmlNodeList ndTopics = xmlTopics.GetElementsByTagName("Topic");
for (int i = 0; i < ndTopics.Count; i++)
{
string _topicCode = ndTopics[i].InnerText[0].ToString();
int _topicValue = ndTopics[i].InnerText[1].ToString();
// Add Topic to Dictionary
dictionary_topics.Add(_topicCode, _topicValue);
}
I thought that this: ndTopics[i].InnerText[0] would return this: topic_aboutme
And this: ndTopics[0].InnerText[1] would return this: 1
Based on the given XML.
I tried displaying ndTopics[0].InnerText and it shows this:
topic_aboutme1
How can I separate the topic_aboutme(<Code>) and 1(<Value>)?
Forgive my naiveness, I'm not really used in utilising XML.
Real easy in Xml Linq :
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 FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
Dictionary<string, string> dict = doc.Descendants("Topic")
.GroupBy(x => (string)x.Element("Code"), y => (string)y.Element("Value"))
.ToDictionary(x => x.Key, y => y.FirstOrDefault());
}
}
}

Finding Specific xml nodes using XDocument

I am trying to find specific nodes in xml using XDocument. The xml also has a namespace which am importing.
Below is the xml specs
<?xml version="1.0" encoding="UTF-8"?>
<tns:response xmlns:tns="http://amazon.com/amazonservices">
<tns:responseDirect>
<tns:responseExtract>
<tns:A>ExtractName</tns:A>
</tns:responseExtract>
<tns:responses>
<tns:Name>Response1</tns:Name>
<tns:Include>No</tns:Include>
</tns:responses>
<tns:responses>
<tns:Name>Response2</tns:Name>
<tns:Include>Yes</tns:Include>
</tns:responses>
<tns:responses>
<tns:Name>Response3</tns:Name>
</tns:responses>
</tns:responseDirect>
I want to retrieve all responses and also only those nodes which have Include nodes present.
I am trying below code to fetch it but I am getting none of the nodes.
XDocument document = XDocument.Parse(xml);
var name = from nm in document.Elements("responses")
select nm;
Can anyone let me know how to fix the issue?I need to only fetch the response node.
Thanks in Advance
Try following :
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 FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
XNamespace ns = doc.Root.GetNamespaceOfPrefix("tns");
var results = doc.Descendants(ns + "responses")
.Where(x => x.Elements(ns + "Include").Any())
.Select(x => new {
include = (string)x.Element(ns + "Include"),
name = (string)x.Element(ns + "Name")
}).ToList();
}
}
}

Add additional elements from a dictionary to the XML during serialization in C#

A part of the XML looks like this.
<element>
<subelment1>text</subelement1>
<subelement2>text2</subelement2>
...
</element>
It has a lot of sub elements.
I would like to add additional elements during the serialization, but the number and name is always different.
So it will be something like this:
<element>
<subelment1>text</subelement1>
<subelement2>text2</subelement2>
...
<additionalelement1>element1text</additionalelement1>
<additionalelement2>element2text</additionalelement2>
...
</element>
The additional elements are stored in a dictionary, where the element name is the key.
Is there a way to accomplish this with the XmlSerializer or any other serializer?
I post this solution a lot :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication34
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
XElement element = doc.Descendants("element").FirstOrDefault();
Dictionary<string,string> dict = element.Elements().GroupBy(x => x.Name.LocalName, y => (string)y)
.ToDictionary(x => x.Key, y => y.FirstOrDefault());
}
}
}

Deserialize XML containing a Dictionary

I have an XML file containing identifiers that I would like Get, the xml look like
<Dictionary
x:TypeArguments="x:String, x:Object"
xmlns="clr-namespace:System.Collections.Generic;assembly=mscorlib"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<List x:TypeArguments="x:Int32" x:Key="key" Capacity="4">
<x:Int32>60371408</x:Int32>
<x:Int32>60371409</x:Int32>
</List>
</Dictionary>
The identifiers that I want to get is 60371408, 60371409
I just found a solution :
Thank you for your reaction :D
Create an XmlSerializer:
var serializer = new XmlSerializer(typeof(Dictionary<string, object>));
...then deserialize. You haven't specified what form this XML is in, whether you have a string or a stream, for example. Here's how you'd deserialize an XML string:
var reader = new StringReader(xml);
var dict = serializer.Deserialize(reader);
Now you have your Dictionary<string, object>, but since values are plain objects, you'll need to cast the values:
var list = (List<int>)dict["key"];
Try xml linq
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
public class Program
{
const string FILENAME = #"c:\temp\test.xml";
public static void Main()
{
XDocument doc = XDocument.Load(FILENAME);
XElement dictionary = doc.Descendants().Where(x => x.Name.LocalName == "Dictionary").FirstOrDefault();
XNamespace xNs = dictionary.GetNamespaceOfPrefix("x");
var results = dictionary.Descendants(xNs + "Int32").Select(x => (int)x).ToList();
}
}
}

What is the best way to read an attribute from an xml string in c#

I have the following xml as string:
<cfdi:Comprobante version="3.0"
xsi:schemaLocation="http://www.sat.gob.mx/cfd/3 http://www.sat.gob.mx/sitio_internet/cfd/3/cfdv3.xsd"
serie="A"
folio="6"
fecha="2011-07-22T13:51:42"
formaDePago="Pago en una sola exhibición"
sello="XlSJYAxauwYbI"
noCertificado="00001000000101242210"
certificado="YtEQOHw02OGx6E="
condicionesDePago="Paguese a mas tardar el 21/08/2011."
subTotal="123"
Moneda="MXN"
total="123"
tipoDeComprobante="ingreso">
<cfdi:Complemento>
<tfd:TimbreFiscalDigital FechaTimbrado="2011-07-22T13:51:47"
UUID="41C8A54F-4956-1BAD-F2CB-48E8343918FD"
noCertificadoSAT="00001000000102616613"
selloCFD="wrwerewe"
version="1.0"
xsi:schemaLocation="http://www.sat.gob.mx/TimbreFiscalDigital http://www.sat.gob.mx/sitio_internet/timbrefiscaldigital/TimbreFiscalDigital.xsd"/>
</cfdi:Complemento>
</cfdi:Comprobante>
I want to read the attribute UUID inside the node tfd:TimbreFiscalDigital so I was wondering how to do this using c#, this might be silly but please understand I'm new in c#.
Note: This xml is inside a string, not in a file (our provider's webservice returns the xml as string, is not our fault)
Note2: I can use Linq, or any other library, that's not a prob
Thanks!!
I wrapped this in a root node declaring the namespaces. I'm also using XPath to query for the node.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Xml.XPath;
using System.Xml;
class Program
{
static void Main(string[] args)
{
var doc = #"
<Root xmlns:xsi='http://someuri' xmlns:cfdi='http://someuri2' xmlns:tfd='http://someuri3'>
<cfdi:Comprobante version='3.0'
xsi:schemaLocation='http://www.sat.gob.mx/cfd/3 http://www.sat.gob.mx/sitio_internet/cfd/3/cfdv3.xsd'
serie='A'
folio='6'
fecha='2011-07-22T13:51:42'
formaDePago='Pago en una sola exhibición'
sello='XlSJYAxauwYbI'
noCertificado='00001000000101242210'
certificado='YtEQOHw02OGx6E='
condicionesDePago='Paguese a mas tardar el 21/08/2011.'
subTotal='123'
Moneda='MXN'
total='123'
tipoDeComprobante='ingreso'>
<cfdi:Complemento>
<tfd:TimbreFiscalDigital FechaTimbrado='2011-07-22T13:51:47'
UUID='41C8A54F-4956-1BAD-F2CB-48E8343918FD'
noCertificadoSAT='00001000000102616613'
selloCFD='wrwerewe'
version='1.0'
xsi:schemaLocation='http://www.sat.gob.mx/TimbreFiscalDigital http://www.sat.gob.mx/sitio_internet/timbrefiscaldigital/TimbreFiscalDigital.xsd'/>
</cfdi:Complemento>
</cfdi:Comprobante>
</Root>";
var uuid = XDocument.Parse(doc)
var uuid = XDocument.Parse(doc)
.XPathSelectElement("//*[local-name() = 'TimbreFiscalDigital']")
.Attribute("UUID").Value;
// Work with uuid
Console.Read();
}
}
Because you have namespace prefixes, you'll have to use XNamespace instances to help you reference the elements.
// We use these to establish our namespace prefixes
XNamespace cfdi = #"http://www.sat.gob.mx/cfd/3";
XNamespace tfd = #"http://www.sat.gob.mx/TimbreFiscalDigital";
var xdoc = XDocument.Parse(xml);
// Walk down the XML tree to tfd:TimbreFiscalDigital
var elt = xdoc.Element(cfdi + "Comprobante")
.Element(cfdi + "Complemento")
.Element(tfd + "TimbreFiscalDigital");
// Alternately
// var elt = xdoc.Descendants(tfd + "TimbreFiscalDigital")
// .First();
var uuid = (string)elt.Attribute("UUID");
// You can convert attributes and element values to lots of built-in types
// See the Explicit Conversions for XAttribute and XElement on MSDN
var date = (DateTime)elt.Attribute("FechaTimbrado");
Further reading:
MSDN: XElement Operators
MSDN: XAttribute Operators
I find linq's XDocument and related classes to be particularly simple and straightforward to use:
string uuid = XDocument.Parse(xmlString)
.Descendants("TimbreFiscalDigital")
.Attributes("UUID")
.First()
.Value;

Categories

Resources