从ASP.NET Web API中删除XML中的命名空间

Mik*_*ynn 36 xml asp.net-web-api

如何使用Web API从下面的xml响应中删除命名空间?

<ApiDivisionsResponse xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/GrassrootsHoops.Models.Api.Response">
<Divisions xmlns:d2p1="http://schemas.datacontract.org/2004/07/GrassrootsHoops.Data.Entities">
<d2p1:Page>1</d2p1:Page>
<d2p1:PageSize>10</d2p1:PageSize>
<d2p1:Results xmlns:d3p1="http://schemas.datacontract.org/2004/07/GrassrootsHoops.Models.Api.Response.Divisions"/>
<d2p1:Total>0</d2p1:Total>
</Divisions>
</ApiDivisionsResponse>
Run Code Online (Sandbox Code Playgroud)

Fil*_*p W 41

选项1是切换到使用XmlSerializerGlobalConfiguration:

config.Formatters.XmlFormatter.UseXmlSerializer = true;
Run Code Online (Sandbox Code Playgroud)

选项2是用你的模型装饰

[DataContract(Namespace="")]
Run Code Online (Sandbox Code Playgroud)

(如果你这样做,你需要用[DataMember]属性装饰成员).

  • 我正在设置`UseXmlSerializer = true;`但格式与OP写的相同 (6认同)
  • `[DataContract()]`属性需要引用[`System.Runtime.Serialization`](http://msdn.microsoft.com/en-us/library/kd1dc9w5.aspx)库 (5认同)
  • 我做了UseXmlSerializer,现在它只使用JSON. (2认同)

小智 21

如果你愿意用XmlRoot来装饰你的模型,这是一个很好的方法.假设你有一辆带门的汽车.默认的WebApi配置将返回如下内容:

<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>
Run Code Online (Sandbox Code Playgroud)

这就是你想要的:

<car>
    <doors>
        <door>
            <color>black</color>
        </door>
    </doors>
</car>
Run Code Online (Sandbox Code Playgroud)

这是模型:

[XmlRoot("car")]
public class Car
{
    [XmlArray("doors"), XmlArrayItem("door")]
    public Door[] Doors { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

您需要做的是创建一个自定义XmlFormatter,如果XmlRoot属性中没有定义名称空间,它将具有空名称空间.出于某种原因,默认格式化程序始终添加两个默认命名空间.

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

最后要做的是在WebApiContext中添加新的格式化程序.请务必删除(或清除)旧的XmlMediaTypeFormatter

public static class WebApiContext
{
    public static void Register(HttpConfiguration config)
    {
        ...
        config.Formatters.Clear();
        config.Formatters.Add(new CustomNamespaceXmlFormatter{UseXmlSerializer=true});
        ...
    }
}   
Run Code Online (Sandbox Code Playgroud)

  • 做得好.但是,请注意:`config.Formatters.Add(new IgnoreNamespacesXmlMediaTypeFormatter {UseXmlSerializer = true});`应该在发送`POST`数据时设置`,`FromBody`将无法"序列化"它. (3认同)

Kon*_*man 6

我喜欢pobed2的回答.但我需要CustomNamespaceXmlFormatter允许我指定一个默认的根名称空间,当该XmlRoot属性丢失时以及它存在且Namespace属性中没有值时使用(也就是说,该属性仅用于设置根元素名称) .所以我创建了一个改进的版本,以防万一它对某人有用:

public class CustomNamespaceXmlFormatter : XmlMediaTypeFormatter
{
    private readonly string defaultRootNamespace;

    public CustomNamespaceXmlFormatter() : this(string.Empty)
    {
    }

    public CustomNamespaceXmlFormatter(string defaultRootNamespace)
    {
        this.defaultRootNamespace = defaultRootNamespace;
    }

    public override Task WriteToStreamAsync(
        Type type, 
        object value, 
        Stream writeStream,
        HttpContent content,
        TransportContext transportContext)
    {
        var xmlRootAttribute = type.GetCustomAttribute<XmlRootAttribute>(true);
        if(xmlRootAttribute == null)
            xmlRootAttribute = new XmlRootAttribute(type.Name)
            {
                Namespace = defaultRootNamespace
            };
        else if(xmlRootAttribute.Namespace == null)
            xmlRootAttribute = new XmlRootAttribute(xmlRootAttribute.ElementName)
            {
                Namespace = defaultRootNamespace
            };

        var xns = new XmlSerializerNamespaces();
        xns.Add(string.Empty, xmlRootAttribute.Namespace);

        return Task.Factory.StartNew(() =>
        {
            var serializer = new XmlSerializer(type, xmlRootAttribute);
            serializer.Serialize(writeStream, value, xns);
        });
    }
}
Run Code Online (Sandbox Code Playgroud)