从 ASP.NET Web API 中删除 XML 中的命名空间
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12590801/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Remove namespace in XML from ASP.NET Web API
提问by Mike Flynn
How do I remove the namespace from the xml response below using 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>
回答by Filip W
Option 1 is to switch to using XmlSerializerin GlobalConfiguration:
选项 1 是切换到使用XmlSerializerin GlobalConfiguration:
config.Formatters.XmlFormatter.UseXmlSerializer = true;
Option 2 is to decorate your models with
选项 2 是用
[DataContract(Namespace="")]
(and if you do so, you'd need to decorate the members with [DataMember]attributes).
(如果你这样做,你需要用[DataMember]属性装饰成员)。
回答by pobed2
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 :
如果您愿意用 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>
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.
您需要做的是创建一个自定义的 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);
}
}
}
Last thing to do is add the new formatter in the WebApiContext. Be sure to remove (or clear) the old XmlMediaTypeFormatter
最后要做的是在 WebApiContext 中添加新的格式化程序。请务必删除(或清除)旧的 XmlMediaTypeFormatter
public static class WebApiContext
{
public static void Register(HttpConfiguration config)
{
...
config.Formatters.Clear();
config.Formatters.Add(new CustomNamespaceXmlFormatter{UseXmlSerializer=true});
...
}
}
回答by Konamiman
I like pobed2's answer. But I needed the CustomNamespaceXmlFormatterto allow me to specify a default root namespace to be used when the XmlRootattribute is missing andalso when it is present and has no value in the Namespaceproperty (that is, the attribute is used to set the root element name only). So I created an improved version, here it is in case it's useful for someone:
我喜欢 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);
});
}
}
回答by Pawel Cioch
In the project that keeps response models go to Properties/AssemblyInfo.cs
在保留响应模型的项目中,转到 Properties/AssemblyInfo.cs
Add
添加
using System.Runtime.Serialization;
using System.Runtime.Serialization;
and at the bottom add
并在底部添加
[assembly: ContractNamespace("", ClrNamespace = "Project.YourResponseModels")]
Replace Project.YourResponseModelswith the actual namespace where response models are located.
You need to add one per namespace
替换Project.YourResponseModels为响应模型所在的实际命名空间。您需要为每个命名空间添加一个
回答by Larissa Savchekoo
You could use the next algorithm
你可以使用下一个算法
Put attribute for your class
[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; } }Write method into your Controller or util's class
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()); }Use method SerializeWithoutNamespacesinto Action
[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); } }Don't forget to put some dependencies into StartUp class
public void ConfigureServices(IServiceCollection services) { services.AddMvc() .AddXmlSerializerFormatters() .AddXmlDataContractSerializerFormatters(); }
为您的班级放置属性
[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()); }使用方法SerializeWithoutNamespacesinto Action
[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(); }
回答by Kelly
The CustomNamespaceXmlFormatter class did the trick for me except it caused a memory leak (when my web service got hit hard, the memory kept increasing higher and higher), so I modified how the instances of XmlSerializer are created:
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;
}
}
}
回答by Sql_Tech
This works perfectly
这完美地工作
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);
}

