如何使用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>
答案 0 :(得分:39)
选项1是切换为使用XmlSerializer
中的GlobalConfiguration
:
config.Formatters.XmlFormatter.UseXmlSerializer = true;
选项2是用
装饰你的模型[DataContract(Namespace="")]
(如果你这样做,你需要用[DataMember]
属性装饰成员。)
答案 1 :(得分: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>
这就是你想要的:
<car>
<doors>
<door>
<color>black</color>
</door>
</doors>
</car>
以下是模型:
[XmlRoot("car")]
public class Car
{
[XmlArray("doors"), XmlArrayItem("door")]
public Door[] Doors { get; set; }
}
如果XmlRoot属性中没有定义名称空间,那么您需要创建一个自定义的XmlFormatter,它将具有空名称空间。出于某种原因,默认格式化程序始终添加两个默认名称空间。
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);
}
}
}
最后要做的是在WebApiContext中添加新的格式化程序。请务必删除(或清除)旧的XmlMediaTypeFormatter
public static class WebApiContext
{
public static void Register(HttpConfiguration config)
{
...
config.Formatters.Clear();
config.Formatters.Add(new CustomNamespaceXmlFormatter{UseXmlSerializer=true});
...
}
}
答案 2 :(得分: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);
});
}
}
答案 3 :(得分:3)
在保留响应模型的项目中,转到Properties/AssemblyInfo.cs
添加
using System.Runtime.Serialization;
并在底部添加
[assembly: ContractNamespace("", ClrNamespace = "Project.YourResponseModels")]
将Project.YourResponseModels
替换为响应模型所在的实际命名空间。
您需要为每个命名空间添加一个
答案 4 :(得分:0)
您可以使用下一个算法
为您的课程输入属性
[XmlRoot("xml", Namespace = "")]
public class MyClass
{
[XmlElement(ElementName = "first_node", Namespace = "")]
public string FirstProperty { get; set; }
[XmlElement(ElementName = "second_node", Namespace = "")]
public string SecondProperty { get; set; }
}
将方法写入Controller或util的类
private ContentResult SerializeWithoutNamespaces(MyClass instanseMyClass)
{
var sw = new StringWriter();
var xmlWriter = XmlWriter.Create(sw, new XmlWriterSettings() {OmitXmlDeclaration = true});
var ns = new XmlSerializerNamespaces();
ns.Add("", "");
var serializer = new XmlSerializer(instanseMyClass.GetType());
serializer.Serialize(xmlWriter, instanseMyClass, ns);
return Content(sw.ToString());
}
使用方法 SerializeWithoutNamespaces 进入操作
[Produces("application/xml")]
[Route("api/My")]
public class MyController : Controller
{
[HttpPost]
public ContentResult MyAction(string phrase)
{
var instanseMyClass = new MyClass{FirstProperty ="123", SecondProperty ="789"};
return SerializeWithoutNamespaces(instanseMyClass);
}
}
别忘了在StartUp类中添加一些依赖项
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc()
.AddXmlSerializerFormatters()
.AddXmlDataContractSerializerFormatters();
}
答案 5 :(得分:0)
CustomNamespaceXmlFormatter类帮了我大忙,除了它引起了内存泄漏(当我的Web服务受到重击时,内存越来越高),所以我修改了XmlSerializer实例的创建方式:
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)
{
if (type == typeof(String))
{
//If all we want to do is return a string, just send to output as <string>value</string>
return base.WriteToStreamAsync(type, value, writeStream, content, transportContext);
}
else
{
XmlRootAttribute xmlRootAttribute = (XmlRootAttribute)type.GetCustomAttributes(typeof(XmlRootAttribute), true)[0];
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); **OLD CODE**
var serializer = XmlSerializerInstance.GetSerializer(type, xmlRootAttribute);
serializer.Serialize(writeStream, value, xns);
});
}
}
}
public static class XmlSerializerInstance
{
public static object _lock = new object();
public static Dictionary<string, XmlSerializer> _serializers = new Dictionary<string, XmlSerializer>();
public static XmlSerializer GetSerializer(Type type, XmlRootAttribute xra)
{
lock (_lock)
{
var key = $"{type}|{xra}";
if (!_serializers.TryGetValue(key, out XmlSerializer serializer))
{
if (type != null && xra != null)
{
serializer = new XmlSerializer(type, xra);
}
_serializers.Add(key, serializer);
}
return serializer;
}
}
}
答案 6 :(得分:-3)
这完美无缺
public ActionResult JsonAction(string xxx)
{
XmlDocument xmlDoc2 = new XmlDocument();
xmlDoc2.Load(xmlStreamReader);
XDocument d = XDocument.Parse(optdoc2.InnerXml);
d.Root.Attributes().Where(x => x.IsNamespaceDeclaration).Remove();
foreach (var elem in d.Descendants())
elem.Name = elem.Name.LocalName;
var xmlDocument = new XmlDocument();
xmlDocument.Load(d.CreateReader());
var jsonText = JsonConvert.SerializeXmlNode(xmlDocument);
return Content(jsonText);
}