简体   繁体   中英

When do you have to specify the root node to deserialize xml?

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM