【发布时间】:2010-09-20 12:18:24
【问题描述】:
有没有办法让我在 .NET 中序列化一个对象,而无需 XML 命名空间也自动序列化?似乎默认情况下 .NET 认为应该包含 XSI 和 XSD 命名空间,但我不希望它们在那里。
【问题讨论】:
标签: .net xml-serialization xml-namespaces
有没有办法让我在 .NET 中序列化一个对象,而无需 XML 命名空间也自动序列化?似乎默认情况下 .NET 认为应该包含 XSI 和 XSD 命名空间,但我不希望它们在那里。
【问题讨论】:
标签: .net xml-serialization xml-namespaces
啊……没关系。提出问题后的搜索总是会产生答案。我正在序列化的对象是obj,并且已经被定义。将具有单个空命名空间的 XMLSerializerNamespace 添加到集合中就可以了。
在 VB 中是这样的:
Dim xs As New XmlSerializer(GetType(cEmploymentDetail))
Dim ns As New XmlSerializerNamespaces()
ns.Add("", "")
Dim settings As New XmlWriterSettings()
settings.OmitXmlDeclaration = True
Using ms As New MemoryStream(), _
sw As XmlWriter = XmlWriter.Create(ms, settings), _
sr As New StreamReader(ms)
xs.Serialize(sw, obj, ns)
ms.Position = 0
Console.WriteLine(sr.ReadToEnd())
End Using
在 C# 中像这样:
//Create our own namespaces for the output
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
//Add an empty namespace and empty value
ns.Add("", "");
//Create the serializer
XmlSerializer slz = new XmlSerializer(someType);
//Serialize the object with our own namespaces (notice the overload)
slz.Serialize(myXmlTextWriter, someObject, ns);
【讨论】:
q1 废话的方法了吗?
如果您想摆脱多余的xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 和xmlns:xsd="http://www.w3.org/2001/XMLSchema",但仍保留您自己的命名空间xmlns="http://schemas.YourCompany.com/YourSchema/",则使用与上述相同的代码,除了这个简单的更改:
// Add lib namespace with empty prefix
ns.Add("", "http://schemas.YourCompany.com/YourSchema/");
【讨论】:
如果您想删除命名空间,您可能还想删除版本,为了节省您的搜索,我已经添加了该功能,因此下面的代码将同时执行这两项操作。
我还将它包装在一个通用方法中,因为我正在创建非常大的 xml 文件,这些文件太大而无法在内存中序列化,因此我将输出文件分解并序列化为更小的“块”:
public static string XmlSerialize<T>(T entity) where T : class
{
// removes version
XmlWriterSettings settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
XmlSerializer xsSubmit = new XmlSerializer(typeof(T));
using (StringWriter sw = new StringWriter())
using (XmlWriter writer = XmlWriter.Create(sw, settings))
{
// removes namespace
var xmlns = new XmlSerializerNamespaces();
xmlns.Add(string.Empty, string.Empty);
xsSubmit.Serialize(writer, entity, xmlns);
return sw.ToString(); // Your XML
}
}
【讨论】:
StringWriter 默认为 UTF-16 编码,这可能会导致下游反序列化问题。 using (var reader = XmlReader.Create(stream)){ reader.Read(); } 这会引发异常,因为声明声明它是 UTF-16,而内容实际上是写为 UTF-8。 System.Xml.XmlException: 'There is no Unicode byte order mark. Cannot switch to Unicode.'
XmlReader,您可以使用var streamReader = new StreamReader(stream, System.Text.Encoding.UTF8, true); 如果找到 true 将使用 BOM,否则使用您提供的默认值。
我建议这个助手类:
public static class Xml
{
#region Fields
private static readonly XmlWriterSettings WriterSettings = new XmlWriterSettings {OmitXmlDeclaration = true, Indent = true};
private static readonly XmlSerializerNamespaces Namespaces = new XmlSerializerNamespaces(new[] {new XmlQualifiedName("", "")});
#endregion
#region Methods
public static string Serialize(object obj)
{
if (obj == null)
{
return null;
}
return DoSerialize(obj);
}
private static string DoSerialize(object obj)
{
using (var ms = new MemoryStream())
using (var writer = XmlWriter.Create(ms, WriterSettings))
{
var serializer = new XmlSerializer(obj.GetType());
serializer.Serialize(writer, obj, Namespaces);
return Encoding.UTF8.GetString(ms.ToArray());
}
}
public static T Deserialize<T>(string data)
where T : class
{
if (string.IsNullOrEmpty(data))
{
return null;
}
return DoDeserialize<T>(data);
}
private static T DoDeserialize<T>(string data) where T : class
{
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(data)))
{
var serializer = new XmlSerializer(typeof (T));
return (T) serializer.Deserialize(ms);
}
}
#endregion
}
:)
【讨论】:
new XmlSerializerNamespaces(new[] {XmlQualifiedName.Empty}) 而不是 new XmlSerializerNamespaces(new[] {new XmlQualifiedName("", "")}) 是一种更清晰的编码方式。
如果在从生成的类序列化为 xml 时(例如:使用 xsd.exe 时),如果您无法摆脱每个元素的额外 xmlns 属性,那么您会得到类似:
<manyElementWith xmlns="urn:names:specification:schema:xsd:one" />
然后我会与你分享对我有用的东西(以前的答案和我发现的 here 的混合)
如下明确设置所有不同的 xmlns:
Dim xmlns = New XmlSerializerNamespaces()
xmlns.Add("one", "urn:names:specification:schema:xsd:one")
xmlns.Add("two", "urn:names:specification:schema:xsd:two")
xmlns.Add("three", "urn:names:specification:schema:xsd:three")
然后将其传递给序列化
serializer.Serialize(writer, object, xmlns);
您将在根元素中声明三个命名空间,并且不再需要在其他元素中生成相应的前缀
<root xmlns:one="urn:names:specification:schema:xsd:one" ... />
<one:Element />
<two:ElementFromAnotherNameSpace /> ...
【讨论】:
XmlWriterSettings settings = new XmlWriterSettings
{
OmitXmlDeclaration = true
};
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
StringBuilder sb = new StringBuilder();
XmlSerializer xs = new XmlSerializer(typeof(BankingDetails));
using (XmlWriter xw = XmlWriter.Create(sb, settings))
{
xs.Serialize(xw, model, ns);
xw.Flush();
return sb.ToString();
}
【讨论】: