4

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?

1 Answer 1

3

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

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you kindly! I was thinking I'd be able to get away without a root class, which obviously isn't going to work.
Hi, you may check the second approach as well.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.