Problems with XML deserialize - c#

I am trying to deserialize and read a simple XML file, the following code finishes without error, but the deserialization was not performed.
My message has one node, three elements below that. After the Deserialize call, I am trying to read one of the properties and it is empty.
public class Program
{
private string response = #"<?xml version=""1.0""?>
<ApplicationException xmlns = ""http://schemas.datacontract.org/2004/07/System"" xmlns:x=""http://www.w3.org/2001/XMLSchema"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance"">
<Name xmlns = """" i:type=""x:string"">System.ApplicationException</Name>
<Message xmlns = """" i:type=""x:string"">Error Message 12345</Message>
<DataPoints xmlns = """" i:nil=""true""/>
</ApplicationException>";
private XElement xElement;
private ExceptionClass theException;
public TestXML()
{
xElement = XElement.Parse(response);
var xmlSerializer = new XmlSerializer(typeof(ExceptionClass));
using (var reader = xElement.CreateReader())
{
theException = (ExceptionClass)xmlSerializer.Deserialize(reader);
}
Console.WriteLine(theException.Message); // nothing is showing up
}
}
[XmlRoot(Namespace = "http://schemas.datacontract.org/2004/07/System",
ElementName = "ApplicationException")]
public class ExceptionClass
{
public String Name { get; set; }
public String Message { get; set; }
public String DataPoints { get; set; }
}

The problem is you are setting the XML namespaces of the elements to null whereas the root element has a namespace. Try this:
public class ExceptionClass
{
[XmlElement(Namespace="")]
public String Name { get; set; }
[XmlElement(Namespace = "")]
public String Message { get; set; }
[XmlElement(Namespace = "")]
public String DataPoints { get; set; }
}
That should work...

Related

Null value on xml deserialization using [XmlAttribute]

I have the following XML;
<?xml version="1.0" encoding="UTF-8" ?>
<feedback>
<report_metadata>
<org_name>example.com</org_name>
</report_metadata>
</feedback>
and the following Feedback.cs class;
[XmlRoot("feedback", Namespace = "", IsNullable = false)]
public class Feedback
{
[XmlElement("report_metadata")]
public MetaData MetaData { get; set; }
}
[XmlType("report_metadata")]
public class MetaData
{
[XmlAttribute("org_name")]
public string Organisation { get; set; }
}
When I attempt to deserialize, the value for Organisation is null.
var xml = System.IO.File.ReadAllText("example.xml");
var serializer = new XmlSerializer(typeof(Feedback));
using (var reader = new StringReader(input))
{
var feedback = (Feedback)serializer.Deserialize(reader);
}
Yet, when I change Feedback.cs to the following, it works (obviously the property name has changed).
[XmlType("report_metadata")]
public class MetaData
{
//[XmlAttribute("org_name")]
public string org_name { get; set; }
}
I want the property to be Organisation, not org_name.
In the example XML file org_name is an XML element, not an XML attribute. Changing
[XmlAttribute("org_name")] to [XmlElement("org_name")] at the Organisation property will deserialize it as an element:
[XmlElement("org_name")]
public string Organisation { get; set; }
probably just typo
[XmlAttribute("org_name")]
public string Organisation { get; set; }
was supposed to be
[XmlElement("org_name")]
public string Organisation { get; set; }
Try to modify your Xml classes like
[XmlRoot(ElementName = "report_metadata")]
public class MetaData
{
[XmlElement(ElementName = "org_name")]
public string Organisation { get; set; }
}
[XmlRoot(ElementName = "feedback")]
public class Feedback
{
[XmlElement(ElementName = "report_metadata")]
public MetaData MetaData { get; set; }
}
Then you will get your desired output like
class Program
{
static void Main(string[] args)
{
Feedback feedback = new Feedback();
var xml = System.IO.File.ReadAllText(#"C:\Users\Nullplex6\source\repos\ConsoleApp4\ConsoleApp4\Files\XMLFile1.xml");
var serializer = new XmlSerializer(typeof(Feedback));
using (var reader = new StringReader(xml))
{
feedback = (Feedback)serializer.Deserialize(reader);
}
Console.WriteLine($"Organization: {feedback.MetaData.Organisation}");
Console.ReadLine();
}
}
Output:

c# parse string to xml using StringReader

I have an XML and I load it in an class.
This is my XML
<out_policySystem xmlns:msl="http://www.ibm.com/xmlmap" xmlns:io="" xmlns:xs4xs="http://www.w3.org/2001/XMLSchema">
<BGBAResultadoOperacion>
<Severidad>OK</Severidad>
</BGBAResultadoOperacion>
<permiteOperar>true</permiteOperar>
<Lista xmlns:ns0=\"http://CalypsoPolicySystem_lib/service\">
<Codigo>ODM-006</Codigo>
<Descripcion>Aviso</Descripcion>
<DescripcionTecnica>XXXX</DescripcionTecnica>
</Lista>
</out_policySystem>
I have define my classes like this.
[XmlRoot(ElementName = "out_policySystem")]
public partial class output_policySystem
{
public BGBAResultadoOperacion BGBAResultadoOperacion { get; set; }
public bool permiteOperar { get; set; }
public List[] Lista { get; set; }
}
public partial class BGBAResultadoOperacion
{
public string Severidad { get; set; }
}
public partial class List
{
public string Codigo { get; set; }
public string Descripcion { get; set; }
public string DescripcionTecnica { get; set; }
}
I read this like this.
XmlNodeList elemlist = xDoc.GetElementsByTagName("out_policySystem");
string result = elemlist[0].InnerXml;
XmlSerializer serializer = new XmlSerializer(typeof(BGBAResultadoOperacion));
using (StringReader reader = new StringReader(result))
{
result = (BGBAResultadoOperacion)(serializer.Deserialize(reader));
}
the value of result is this.
<BGBAResultadoOperacion><Severidad>OK</Severidad></BGBAResultadoOperacion><permiteOperar>true</permiteOperar><Lista><Codigo>ODM-006</Codigo><Descripcion>Aviso</Descripcion><DescripcionTecnica>xxxx</DescripcionTecnica></Lista>
What I need is to get the value of BGBAResultadoOperacion
when i set
using (StringReader reader = new StringReader(result))
{
result = (BGBAResultadoOperacion)(serializer.Deserialize(reader));
}
result get XML error...
There are multiple root elements. Line 1, position 76.
XML node out_policySystem has three root elements inside it. I need to parse only BGBAResultadoOperacion
How can I get it?
Thanks
That's because of this line:
elemlist[0].InnerXml
Which returns an XML Fragment, not an XML Document.
<BGBAResultadoOperacion>
<Severidad>OK</Severidad>
</BGBAResultadoOperacion>
<permiteOperar>true</permiteOperar>
<Lista xmlns:ns0=\"http://CalypsoPolicySystem_lib/service\">
<Codigo>ODM-006</Codigo>
<Descripcion>Aviso</Descripcion>
<DescripcionTecnica>XXXX</DescripcionTecnica>
</Lista>
So either use the .OuterXML, or use XElement.CreateReader() as described in the answer here: Serialize an object to XElement and Deserialize it in memory

Tricks for deserialize this xml element

A legacy application transmits data as xml elements.
<frame>
<reply>
<id>value_id</id>
<resultCode>value</resultCode>
<readSampleIDs>
<returnValue>
<Sample>
<SampleID> value_SampleID </SampleID>
<SamplePC> value_SamplePC </SamplePC>
<antennaName> value_antennaName </antennaName>
<channel> value_channel </channel>
<power> value_power </power>
<polarization> value_polarization </polarization>
<inventoried> value_inventoried </inventoried>
</Sample>
…
<Sample>
…
</Sample>
</returnValue>
</readSampleIDs>
</reply>
Currently the information is extracted parsing the string word by word.
I think that xml element can be deserialized into an object directly with XmlSerializer but I have some doubts on how to do it.
The element frame contains only one reply. Do I really need two different classes ?
Inside returnValue there can be zero or more Sample. In my class what is the correct type, List<Sample> or Sample[] ? Is there a real difference between the two options during deserialization ?
Most fields inside Sample are optional. How do I model this ?
When an object is serialized with XmlSerializer information about xml version and additional attributes on root element are automatically added such as:
<?xml version="1.0" encoding="utf-8"?>
<PurchaseOrder xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.cpandl.com">
They are not present in my example code so I'm afraid deserialization can complain about it and possibly fail.
Thanks
Filippo
If your xml contains a namespace (like in your example) then you can use these classes:
[XmlRoot(ElementName = "Sample")]
public class Sample
{
[XmlElement(ElementName = "SampleID")]
public string SampleID { get; set; }
[XmlElement(ElementName = "SamplePC")]
public string SamplePC { get; set; }
[XmlElement(ElementName = "antennaName")]
public string AntennaName { get; set; }
[XmlElement(ElementName = "channel")]
public string Channel { get; set; }
[XmlElement(ElementName = "power")]
public string Power { get; set; }
[XmlElement(ElementName = "polarization")]
public string Polarization { get; set; }
[XmlElement(ElementName = "inventoried")]
public string Inventoried { get; set; }
}
[XmlRoot(ElementName = "readSampleIDs")]
public class ReadSampleIDs
{
[XmlArray(ElementName = "returnValue")]
[XmlArrayItem(ElementName = "Sample")]
public List<Sample> Sample { get; set; }
}
[XmlRoot(ElementName = "reply", Namespace = "http://www.cpandl.com")]
public class Reply
{
[XmlElement(ElementName = "id")]
public string Id { get; set; }
[XmlElement(ElementName = "resultCode")]
public string ResultCode { get; set; }
[XmlElement(ElementName = "readSampleIDs")]
public ReadSampleIDs ReadSampleIDs { get; set; }
}
If you are only interested in node reply and this is the only one. You can deserialize only this node:
XNamespace loNameSpace = "http://www.cpandl.com";
XDocument loDoc = XDocument.Parse(Properties.Settings.Default.TransmitsData);
var loReplyElement = loDoc.Element(loNameSpace.GetName("PurchaseOrder"))
.Element(loNameSpace.GetName("frame"))
.Element(loNameSpace.GetName("reply"));
using (var loReader = loReplyElement.CreateReader())
{
var loSerializer = new XmlSerializer(typeof(Reply));
var loReply = (Reply)loSerializer.Deserialize(loReader);
Console.WriteLine(loReply.Id);
}

Generate list of objects from XML stored in SqlXml variable

I have BIObject class
public class BIObject
{
public string Database { get; set; }
public string Schema { get; set; }
public string Name { get; set; }
public string ObjectType { get; set; }
}
and also have below XML
<root>
<objects>
<object database="LynxReporting" schema="dbo" name="rptusp_GLTDRSummary" type="P"/>
<object database="IntraDay" schema="dbo" name="BMHGLCloseDetails" type="T"/>
<object database="LynxReporting" schema="dbo" name="factGeneralLedger" type="P"/>
</objects>
</root>
I need to create List<IBObject> from the XML
Note: I load the XML from database into a property of type SqlXml so I need to convert SqlXml to List<IBObject>
Looked at couple of answers but could not figure out how I can do that.
EDIT:
I used below code
using (StringReader reader = new StringReader(myXmlString))
{
XmlSerializer serializer = new XmlSerializer(typeof(List<BIObject>));
List<BIObject> objs = (List<BIObject>)serializer.Deserialize(reader);
}
but got error
There is an error in XML document (1, 2).
and
root xmlns='' was not expected.
Create a class which "represent" your xml structure
[XmlRoot("root")]
public class BIObjects
{
public BIObjects()
{
Objects = new List<BIObject>();
}
[XmlArray("objects")]
[XmlArrayItem("object")]
public List<BIObject> Objects { get; set; }
}
public class BIObject
{
[XmlAttribute("database")]
public string Database { get; set; }
[XmlAttribute("schema")]
public string Schema { get; set; }
[XmlAttribute("name")]
public string Name { get; set; }
[XmlAttribute("type")]
public string ObjectType { get; set; }
}
Then use same serializer code you provide in the question
using (StringReader reader = new StringReader(myXmlString))
{
XmlSerializer serializer = new XmlSerializer(typeof(BIObjects));
var objs = (BIObjects)serializer.Deserialize(reader);
// use results
// foreach(BIObject obj in objs.Objects)
}

XML Deserialization error: xxxxx was not expected

I know there are several posts out there with this topic, but I can't seem to figure out what is the problem here. I have serialized and deserialized xml several times, and never had this error.
The exception message is:
There is an error in XML document (1, 2).
With InnerException:
<InvoiceChangeRequest xmlns=''> was not expected.
XML file I want to deserialize:
<ns1:InvoiceChangeRequest xmlns:ns1="http://kmd.dk/fie/external_invoiceDistribution">
<CONTROL_FIELDS>
<STRUCTURID>0000000001</STRUCTURID>
<OPERA>GET</OPERA>
<WIID>000050371220</WIID>
</CONTROL_FIELDS>
<HEADER_IN>
<MANDT>751</MANDT>
<BELNR>1234567890</BELNR>
</HEADER_IN>
<ITEMS>
<ITEM_FIELDS_IN>
<BUZEI>001</BUZEI>
<BUKRS>0020</BUKRS>
</ITEM_FIELDS_IN>
</ITEMS>
</ns1:InvoiceChangeRequest>
Class I'm trying to deserialize to:
[XmlRoot(Namespace = "http://kmd.dk/fie/external_invoiceDistribution", IsNullable = false)]
public class InvoiceChangeRequest
{
[XmlElement("CONTROL_FIELDS")] public ControlFields Styrefelter;
[XmlElement("HEADER_IN")] public HeaderIn HeaderfelterInd;
[XmlElement("ITEMS")] public Items Linjer;
}
public class HeaderIn
{
[XmlElement("MANDT")] public string Kommunenummer;
[XmlElement("BELNR")] public string RegnskabsbilagsNummer;
}
public class Items
{
[XmlElement("ITEM_FIELDS_IN")] public Itemfield[] ItemfelterInd;
}
public class Itemfield
{
[XmlElement("BUZEI")] public string Linjenummer;
[XmlElement("BUKRS")] public string Firmakode;
}
Deserialization code:
XmlSerializer serializer = new XmlSerializer(typeof(InvoiceChangeRequest));
var request = serializer.Deserialize(new StringReader(output)) as InvoiceChangeRequest;
In your XML file your root element is the namespace http://kmd.dk/fie/external_invoiceDistribution with prefix ns1.
The element <CONTROL_FIELDS> isn't because it isn't prefixed. Your serialization class doesn't take this into account though. That means that it expects that <CONTROL_FIELDS> and the other elements are ALSO in the ns1 namespace.
To get the serializer parse the elements correctly add the Namespace to the elements, setting it to an empty string:
[XmlRoot(Namespace = "http://kmd.dk/fie/external_invoiceDistribution", IsNullable = false)]
public class InvoiceChangeRequest
{
[XmlElement("CONTROL_FIELDS", Namespace = "")]
public ControlFields Styrefelter { get; set; }
[XmlElement("HEADER_IN", Namespace = "")]
public HeaderIn HeaderfelterInd { get; set; }
[XmlElement("ITEMS", Namespace = "")]
public Items Linjer { get; set; }
}
This will de-serialize the given XML as intended.
In case of de-serialization issues I often create the classes in memory and then serialize that so I can inspect the resulting XML. That often gives clues on what is missing or being added compared to the input document:
var ms = new MemoryStream();
serializer.Serialize(ms, new InvoiceChangeRequest {
Styrefelter = new ControlFields { Opera="test"}
});
var s = Encoding.UTF8.GetString(ms.ToArray());
And then inspect s for differences.
You can replace 'ns1:' with string.Empty.
Below classes should serialize.
public class Item
{
[XmlElement("BUZEI")]
public string Buzei { get; set; }
[XmlElement("BUKRS")]
public string Bukrs { get; set; }
}
public class Header
{
[XmlElement("MANDT")]
public string Mandt { get; set; }
[XmlElement("BELNR")]
public string Belnr { get; set; }
}
public class ControlFields
{
[XmlElement("STRUCTURID")]
public string StructuredId { get; set; }
[XmlElement("OPERA")]
public string Opera { get; set; }
[XmlElement("WIID")]
public string Wild { get; set; }
}
public class InvoiceChangeRequest
{
[XmlElement("CONTROL_FIELDS")]
public ControlFields ControlFields { get; set; }
[XmlElement("HEADER_IN")]
public Header Header { get; set; }
[XmlArray("ITEMS")]
[XmlArrayItem("ITEM_FIELDS_IN")]
public List<Item> Items { get; set; }
}

Categories

Resources