0

I am trying to deserialize xml coming from a web API service. It works only if I instantiate the XmlSerializer object with the root node- XmlRootAttribute type- that specifies the name of the root node and the namespace. If it is proper xml with only one root node, why do I need to tell it the name of the root? I see examples where people aren't doing that. I'd like to keep this as generic as possible.

XML

This is the code to deserialize. I'd like the commented out line to work where I don't specify the root node, but it gives the error at the bottom.

public static T xmlToObject<T>(string strXML)
        {
            XmlRootAttribute xRoot = new XmlRootAttribute();
            xRoot.ElementName = "QIMonthReturn";
            xRoot.Namespace = "QI.Measures.API";

            XmlSerializer serializer = new XmlSerializer(typeof(T), xRoot);
            //XmlSerializer serializer = new XmlSerializer(typeof(T)); 

            StringReader rdr = new StringReader(strXML);

            return (T)serializer.Deserialize(rdr);
        }

Error (I took out angle brackets):

{"There is an error in XML document (2, 2)."}
{"QIMonthReturn xmlns='QI.Measures.API' was not expected."}

Classes:

public class QIMonth
{
    [XmlElement(ElementName = "Date", DataType = "dateTime")]
    public DateTime Date { get; set; }

    [XmlElement(ElementName = "Numerator", DataType = "boolean")]
    public bool Numerator { get; set; }

    [XmlElement(ElementName = "Denominator", DataType = "boolean")]
    public bool Denominator { get; set; }
}   

[XmlRoot("QIMonthReturn")]
public class QIMonthReturn
{
    public QIMonthReturn()
    {         
        Months = new List<QIMonth>();
    }

    [XmlElement(ElementName = "PatientKey")]
    public string PatientKey { get; set; }

    [XmlArray("Months"), XmlArrayItem("QIMonth")]  
    public List<QIMonth> Months { get; set; }
}

I did have XmlRoot attribute above QIMonth but took it out, don't know if that was needed.

Where I'm adding the namespace:

public static void Register(HttpConfiguration config)
    {           
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        config.Formatters.Clear();
        config.Formatters.Add(new CustomNamespaceXmlFormatter("QI.Measures.API") { UseXmlSerializer = true });
    }
Kelly
  • 867
  • 2
  • 17
  • 30

1 Answers1

0

If you add the namespace to your model class, your code will work. In your question, you had the namespace redacted, so I made one up.

<?xml version="1.0" ?>
<QIMonthReturn xmlns="SomeNamespaceHere">
    <PatientKey>25</PatientKey>
    <Months>
        <QIMonth>
            <Date>2018-05-03T11:13:02.1312881-04:00</Date>
            <Numerator>false</Numerator>
            <Denominator>true</Denominator>
        </QIMonth>
    </Months>
</QIMonthReturn>


[XmlRoot("QIMonthReturn", Namespace="SomeNamespaceHere")]
public class QIMonthReturn
{
    public QIMonthReturn()
    {
        Months = new List<QIMonth>();
    }

    [XmlElement(ElementName = "PatientKey")]
    public string PatientKey { get; set; }

    [XmlArray("Months"), XmlArrayItem("QIMonth")]
    public List<QIMonth> Months { get; set; }
}

public static T xmlToObject<T>(string strXML)
{
    XmlSerializer serializer = new XmlSerializer(typeof(T));

    StringReader rdr = new StringReader(strXML);

    return (T)serializer.Deserialize(rdr);
}

Referencing Marc's answer

John Kraft
  • 6,646
  • 4
  • 36
  • 53
  • I forgot to mention that I am adding the namespace in another place in the WebApiConfig class since I add a custom class to do XML formatting so it won't add the two namespaces Web API automatically adds. I will add that as well (I fear my question is getting very bloated) – Kelly May 03 '18 at 17:28
  • 1
    I didn't see how you added the namespace to the XmlRoot attribute- now that I did that, I am able to run it without specifying the namespace when deserializing (and I still have just one namespace!). Sweet – Kelly May 03 '18 at 18:34