XML Deserialization with multiple namespaces - c#

I'm trying to deserialize the following xml into an Object.
Xml got multiple namespaces.
I tried to deserialize the Xml into an object.
The object (data) has a reference to the LastChannel Object.
But when i ask for data.channel which should give me the LastChannel, i get a nullpointer.
Xml:
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://purl.org/rss/1.0/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:mp="http://www.tagesschau.de/rss/1.0/modules/metaplus/"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
<title>title</title>
<description>Default description</description>
<dc:date>2013-04-15 13:27:06</dc:date>
<sy:updateBase>2013-04-15 13:27:06</sy:updateBase>
<sy:updatePeriod>hourly</sy:updatePeriod>
<sy:updateFrequency>12</sy:updateFrequency>
</channel>
</rdf:RDF>
The objects look like this:
[XmlRoot("RDF", Namespace = "http://www.w3.org/1999/02/22-rdf-syntax-ns#")]
public class LastRss
{
[XmlElement("channel")]
public LastChannel channel { get; set; }
}
and
public class LastChannel
{
[XmlElement("title")]
public string title { get; set; }
[XmlElement("description")]
public string description { get; set; }
[XmlElement("date", Namespace = "http://purl.org/dc/elements/1.1/")]
public DateTime date { get; set; }
[XmlElement("updateBase", Namespace = "http://purl.org/rss/1.0/modules/syndication/")]
public DateTime updateBase { get; set; }
[XmlElement("updatePeriod", Namespace = "http://purl.org/rss/1.0/modules/syndication/")]
public string updatePeriod { get; set; }
[XmlElement("updateFrequency", Namespace = "http://purl.org/rss/1.0/modules/syndication/")]
public int updateFrequency { get; set; }
}
Anybody sees why the data.channel ist null?
Serializer:
LastRss data = new LastRss();
XmlSerializer serializer = new XmlSerializer(typeof(LastRss));
System.IO.TextReader reader = new System.IO.StringReader(xml);
try
{
object o = serializer.Deserialize(reader);
data = (LastRss)o;
}

Your channel is in the default xmlns, viz http://purl.org/rss/1.0/
[XmlElement("channel", Namespace = "http://purl.org/rss/1.0/")]
public LastChannel channel { get; set; }
You'll also need to correct the date formats e.g. 2013-04-15**T**13:27:06

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:

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; }
}

How to add xsi:schemaLocation to serialized object

How can I add the following xsi:schemaLocation to a serialized class?
<ern:NewReleaseMessage xmlns:ern="http://ddex.net/xml/2010/ern-main/32"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
LanguageAndScriptCode="en"
xsi:schemaLocation="http://ddex.net/xml/2010/ern-main/32 http://ddex.net/xml/2010/ern-main/32/ern-main.xsd"
MessageSchemaVersionId="2010/ern-main/32">
Here is what I have done so far:
public class NewReleaseMessage
{
[XmlAttribute]
public string LanguageAndScriptCode { get; set; }
[XmlAttribute("schemaLocation", Namespace = "http://ddex.net/xml/2010/ern-main/32")]
public string schemaLocation = "http://ddex.net/xml/2010/ern-main/32 http://ddex.net/xml/2010/ern-main/32/ern-main.xsd";
[XmlAttribute]
public string MessageSchemaVersionId { get; set; }
[XmlElement()]
public MessageHeader MessageHeader { get; set; }
}
When I deserialize the xml to the object in VS I get:
{"The method or operation is not implemented."
There is an error in XML document (5, 44) - This actually points to the line: xsi:schemaLocation="http://ddex.net/xml/2010/ern-main/32 http://ddex.net/xml/2010/ern-main/32/ern-main.xsd"
Soultion:
[XmlAttribute(AttributeName = "schemaLocation", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
public string schemaLocation { get; set; }
Below is what worked for me:
Note : "XmlAttributeAttribute"
[XmlAttributeAttribute(AttributeName = "schemaLocation", Namespace = "http://ddex.net/xml/2010/ern-main/32")]
public string schemaLocation = "http://ddex.net/xml/2010/ern-main/32 http://ddex.net/xml/2010/ern-main/32/ern-main.xsd";

Categories

Resources