If you're willing to decorate your model with XmlRoot, here's a nice way to do it. Suppose you have a car with doors. The default WebApi configuration will return something like :
<car
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<doors>
<door>
<color>black</color>
</door>
</doors>
</car>
This is what you want:
<car>
<doors>
<door>
<color>black</color>
</door>
</doors>
</car>
Here's the model:
[XmlRoot("car")]
public class Car
{
[XmlArray("doors"), XmlArrayItem("door")]
public Door[] Doors { get; set; }
}
What you have to do is create a custom XmlFormatter that will have an empty namespace if there are no namespaces defined in the XmlRoot attribute. For some reason, the default formatter always adds the two default namespaces.
public class CustomNamespaceXmlFormatter : XmlMediaTypeFormatter
{
public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content,
TransportContext transportContext)
{
try
{
var xns = new XmlSerializerNamespaces();
foreach (var attribute in type.GetCustomAttributes(true))
{
var xmlRootAttribute = attribute as XmlRootAttribute;
if (xmlRootAttribute != null)
{
xns.Add(string.Empty, xmlRootAttribute.Namespace);
}
}
if (xns.Count == 0)
{
xns.Add(string.Empty, string.Empty);
}
var task = Task.Factory.StartNew(() =>
{
var serializer = new XmlSerializer(type);
serializer.Serialize(writeStream, value, xns);
});
return task;
}
catch (Exception)
{
return base.WriteToStreamAsync(type, value, writeStream, content, transportContext);
}
}
}
Last thing to do is add the new formatter in the WebApiContext. Be sure to remove (or clear) the old XmlMediaTypeFormatter
public static class WebApiContext
{
public static void Register(HttpConfiguration config)
{
...
config.Formatters.Clear();
config.Formatters.Add(new CustomNamespaceXmlFormatter{UseXmlSerializer=true});
...
}
}