Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deserialization of XML with multiple namespaces

I'm attempting to deserialize an XML response from an API. The data is as follows (I have only included a small chunk for the sake of a small post):

<ns1:alerts xmlns:ns1="http://gov.fema.ipaws.services/feed">
    <alert xmlns="urn:oasis:names:tc:emergency:cap:1.2">
    <identifier>All-Channels-Test-Message-RT_Automation_124_789f95e3-e02f-4e61-8121

My code to deserialize this data is as follows:

var serializer = new XmlSerializer(
    typeof(List<Alert>),
    new XmlRootAttribute("alerts") { Namespace = "http://gov.fema.ipaws.services/feed" });

var alerts = serializer.Deserialize(stream) as Alert[];

In my Alert class, I have attributes set with the namespace and root element for the alert:

[XmlRoot("alert", Namespace = "urn:oasis:names:tc:emergency:cap:1.2")]
public class Alert

When I go to deserialize a list of alert instances, I get a result of 0 instance. I have verified that the response is formatted correctly. There are 1-2 depending on the dummy alerts on the API feed. My guess is I am deserializing incorrectly. How can I deserialize this properly?

like image 892
alexjusti Avatar asked Nov 15 '25 09:11

alexjusti


1 Answers

Approach 1: With Root class

You should have a Root class and contains Alerts property with applying the [XmlElement("alert", Namespace = "urn:oasis:names:tc:emergency:cap:1.2")] attribute to obtain all <alert> elements.

[XmlRoot("alerts", Namespace = "http://gov.fema.ipaws.services/feed")]
public class Root
{
    [XmlElement("alert", Namespace = "urn:oasis:names:tc:emergency:cap:1.2")]
    public List<Alert> Alerts { get;set; }
}


[XmlRoot("alert", Namespace = "urn:oasis:names:tc:emergency:cap:1.2")]
public class Alert 
{
    [XmlElement(ElementName = "identifier")]
    public string Identifier { get; set; }
}

In the caller, you need to deserialize the stream as Root.

var serializer = new XmlSerializer(
            typeof(Root),
            new XmlRootAttribute("alerts") { Namespace = "http://gov.fema.ipaws.services/feed" });

var root = serializer.Deserialize(stream) as Root;
var alerts = root.Alerts;

Demo @ .NET Fiddle


Approach 2: With XPath

You can work with XPath as well without the need of the Root class, although the implementation is slightly complex.

// Load steam to XmlDocument
var xDocument = new XmlDocument();
xDocument.Load(stream);

// Initialize namespaces and tags
var nsm = new XmlNamespaceManager(xDocument.NameTable);
nsm.AddNamespace("ns1", "http://gov.fema.ipaws.services/feed"); 
nsm.AddNamespace("a", "urn:oasis:names:tc:emergency:cap:1.2"); 

// Search XML nodes
var alertXmlNodeList = xDocument.DocumentElement.SelectNodes("/ns1:alerts/a:alert", nsm);

// Iterate XmlNode in XMLNodeList and deserialize to Alert 
List<Alert> alerts = new List<Alert>();
foreach (XmlNode alertXmlNode in alertXmlNodeList)
{
    XmlSerializer serializer = new XmlSerializer(typeof(Alert));
    Alert alert = serializer.Deserialize(new XmlNodeReader(alertXmlNode)) as Alert;
            
    alerts.Add(alert);

    // Or your implementation for managing `alert` directly
}

Demo @ .NET Fiddle

like image 70
Yong Shun Avatar answered Nov 16 '25 22:11

Yong Shun



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!