如何为IXmlSerializable类型添加命名空间前缀



我有以下类定义

[XmlRoot(ElementName = "person",Namespace = "MyNamespace")]
public class Person : IXmlSerializable
{
public string FirstName { get; set; }
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces Namespaces
{
get
{
var xmlSerializerNamespaces = new XmlSerializerNamespaces();
xmlSerializerNamespaces.Add("My", "MyNamespace");
return xmlSerializerNamespaces;
}
}
public string LastName { get; set; }
public XmlSchema GetSchema()
{
return null;
}
/// <exception cref="NotSupportedException"/>
public void ReadXml(XmlReader reader)
{
throw new NotSupportedException();
}
public void WriteXml(XmlWriter writer)
{
writer.WriteElementString("firstName",FirstName);
writer.WriteElementString("lastName", LastName);
}
}

我想用MyNamespace的My:前缀序列化它,所以当我调用代码时

var xmlSerializer = new XmlSerializer(typeof(Person));
var person = new Person
{ FirstName = "John",LastName = "Doe"};            
xmlSerializer.Serialize(Console.Out, person, person.Namespaces);

我期望以下输出:

<?xml version="1.0" encoding="ibm850"?>
<My:person xmlns:My="MyNamespace">
<My:firstName>John</My:firstName>
<My:lastName>Doe</My:lastName>
</My:person>

但取而代之的是,我得到了以下输出:

<?xml version="1.0" encoding="ibm850"?>
<person xmlns="MyNamespace">
<firstName>John</firstName>
<lastName>Doe</lastName>
</person>

我知道,当我使用SerializableAttribute属性而不是从IXmlSerializable继承时,编写前缀是有效的,但我在项目中的类要复杂得多,我不能使用默认的XmlSerializer。

XmlSerializer类型没有提供任何开箱即用的功能来处理此问题
如果您真的需要使用XmlSerializer,那么您最终会得到一个自定义的XmlSerializer实现,它不是很容易扩展的。出于这个原因,下面的实现更多的是概念验证,只是给你一个想法或起点
为了简洁起见,我省略了任何错误处理,只关注您问题中的Person类。要处理任何嵌套的复杂属性,还有一些工作要做。

由于Serialize方法不是virtual,我们将不得不对它们进行阴影处理。其主要思想是将所有重载指向具有自定义实现的单个重载。

由于自定义,我们必须在Person类中通过指定要应用的xml名称空间为其属性编写xml元素时更加明确。

下方的代码

PrefixedXmlSerializer xmlSerializer = new PrefixedXmlSerializer(typeof(Person));
Person person = new Person { 
FirstName = "John", 
LastName = "Doe" 
};
xmlSerializer.Serialize(Console.Out, person, person.Namespaces);

中的结果

<My:person xmlns:My="MyNamespace">
<My:firstName>John</My:firstName>
<My:lastName>Doe</My:lastName>
</My:person>

这一切是否可以接受,取决于你自己
最终,<My:person xmlns:My="MyNamespace">等于<person xmlns="MyNamespace">

人员

[XmlRoot(ElementName = "person", Namespace = NAMESPACE)]
public class Person : IXmlSerializable
{
private const string NAMESPACE = "MyNamespace";
public string FirstName { get; set; }
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces Namespaces
{
get
{
var xmlSerializerNamespaces = new XmlSerializerNamespaces();
xmlSerializerNamespaces.Add("My", NAMESPACE);                
return xmlSerializerNamespaces;
}
}
public string LastName { get; set; }
public XmlSchema GetSchema()
{
return null;
}
/// <exception cref="NotSupportedException"/>
public void ReadXml(XmlReader reader)
{
throw new NotSupportedException();
}   
public void WriteXml(XmlWriter writer)
{
// Specify the xml namespace.
writer.WriteElementString("firstName", NAMESPACE, FirstName);
writer.WriteElementString("lastName", NAMESPACE, LastName);
}
}

前缀XmlSerializer

public class PrefixedXmlSerializer : XmlSerializer
{
XmlRootAttribute _xmlRootAttribute;

public PrefixedXmlSerializer(Type type) : base(type)
{
this._xmlRootAttribute = type.GetCustomAttribute<XmlRootAttribute>();        
}

public new void Serialize(TextWriter textWriter, Object o, XmlSerializerNamespaces namespaces)
{
// Out-of-the-box implementation.
XmlTextWriter xmlTextWriter = new XmlTextWriter(textWriter);
xmlTextWriter.Formatting = Formatting.Indented;
xmlTextWriter.Indentation = 2;
// Call the shadowed version. 
this.Serialize(xmlTextWriter, o, namespaces, null, null);
}

public new void Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
{
// Lookup the xml namespace and prefix to apply.
XmlQualifiedName[] xmlNamespaces = namespaces.ToArray();                                
XmlQualifiedName xmlRootNamespace =
xmlNamespaces
.Where(ns => ns.Namespace == this._xmlRootAttribute.Namespace)
.FirstOrDefault();
// Write the prefixed root element with its xml namespace declaration.
xmlWriter.WriteStartElement(xmlRootNamespace.Name, this._xmlRootAttribute.ElementName, xmlRootNamespace.Namespace);            
// Write the xml namespaces; duplicates will be taken care of automatically.
foreach (XmlQualifiedName xmlNamespace in xmlNamespaces)
{
xmlWriter.WriteAttributeString("xmlns", xmlNamespace.Name , null, xmlNamespace.Namespace);
}
// Write the actual object xml.
((IXmlSerializable)o).WriteXml(xmlWriter);
xmlWriter.WriteEndElement();       
}
}

尝试以下操作。

public void WriteXml(XmlWriter writer)
{
writer.WriteAttributeString("xmlns", "my", null, "MyNamespace");
writer.WriteElementString("firstName", FirstName);
writer.WriteElementString("lastName", LastName);
}

您需要使用XmlSerializer吗?如果没有,请尝试以下代码:

Person.cs

添加新方法:

public void Serialize(XmlWriter writer)
{
writer.WriteStartDocument();
writer.WriteStartElement("My", "Person", "MyNamespace");
writer.WriteElementString("My", "FirstName", "MyNamespace", FirstName);
writer.WriteElementString("My", "LastName", "MyNamespace", LastName);
writer.WriteEndElement();
writer.WriteEndDocument();
}

用法

var person = new Person { FirstName = "John", LastName = "Doe" };
person.Serialize(new XmlTextWriter(Console.Out));

最新更新