我在XML序列化方面遇到了很大的问题。我有两个类,都需要序列化。在继承的类中,我想更改序列化行为,以便将字符串属性序列化为复杂类型。
public class Animal
{
[XmlElement(ElementName = "NAME")]
public string Name { get; set; }
public virtual bool ShouldSerializeName() { return true; }
}
public class Cat : Animal
{
public override bool ShouldSerializeName() { return false; }
[XmlElement(ElementName = "NAME")]
public NameAndType Name2 { get; set; }
}
public class NameAndType
{
public string Name { get; set; }
public string Type { get; set; }
}
...
var cat = new Cat {Name2 = new NameAndType {Name = "LittleCat"}};
new XmlSerializer(typeof(Cat)).Serialize(Console.Out, cat);
我尝试了不同的方法,但我没有找到改变NAME
元素序列化方式的方法。
通过上面的示例,我收到错误消息:
The XML element 'NAME' from namespace '' is already present in the current scope. Use XML attributes to specify another XML name or namespace for the element.
答案 0 :(得分:3)
您收到错误的原因是,在XmlSerializer
code generation期间,代码生成器无法理解NAME
上的两个潜在Cat
元素永远不会出现同时序列化,所以抛出异常。
相反,您可以将XmlAnyElementAttribute
应用于返回XElement
的虚拟属性,然后手动创建并返回适当的XElement
作为层次结构中每个类的名称:
[XmlInclude(typeof(Cat))]
public class Animal
{
[XmlIgnore]
public string Name { get; set; }
[XmlAnyElement]
public virtual XElement XmlName
{
get
{
return Name == null ? null : new XElement("NAME", Name);
}
set
{
Name = (value == null ? null : value.Value);
}
}
}
public class Cat : Animal
{
// Must be cached as per https://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer%28v=vs.110%29.aspx
static XmlSerializer nameSerializer;
static Cat()
{
nameSerializer = new XmlSerializer(typeof(NameAndType), new XmlRootAttribute("NAME"));
}
[XmlIgnore]
public NameAndType Name2 { get; set; }
[XmlAnyElement]
public override XElement XmlName
{
get
{
return (Name2 == null ? null : XObjectExtensions.SerializeToXElement(Name2, nameSerializer, true));
}
set
{
Name2 = (value == null ? null : XObjectExtensions.Deserialize<NameAndType>(value, nameSerializer));
}
}
}
使用扩展方法:
public static class XObjectExtensions
{
public static T Deserialize<T>(this XContainer element)
{
return element.Deserialize<T>(new XmlSerializer(typeof(T)));
}
public static T Deserialize<T>(this XContainer element, XmlSerializer serializer)
{
using (var reader = element.CreateReader())
{
object result = serializer.Deserialize(reader);
if (result is T)
return (T)result;
}
return default(T);
}
public static XElement SerializeToXElement<T>(this T obj)
{
return obj.SerializeToXElement(new XmlSerializer(obj.GetType()), true);
}
public static XElement SerializeToXElement<T>(this T obj, XmlSerializer serializer, bool omitStandardNamespaces)
{
var doc = new XDocument();
using (var writer = doc.CreateWriter())
{
XmlSerializerNamespaces ns = null;
if (omitStandardNamespaces)
(ns = new XmlSerializerNamespaces()).Add("", ""); // Disable the xmlns:xsi and xmlns:xsd lines.
serializer.Serialize(writer, obj, ns);
}
var element = doc.Root;
if (element != null)
element.Remove();
return element;
}
}
对于List<Animal>
,生成这样的XML:
<ArrayOfAnimal xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <Animal> <NAME>duck</NAME> </Animal> <Animal xsi:type="Cat"> <NAME> <Name>Smokey</Name> <Type>Siamese</Type> </NAME> </Animal> </ArrayOfAnimal>
答案 1 :(得分:0)
您在同一图表级别指定了两个具有相同名称的不同XML元素,这是不允许的。
我将提供一个解决方案,但它涉及连接Cat类序列化的类型和名称。如果没有必要序列化NameAndType类,那么继续: 在Animal上,将Name设置为virtual; 在Cat上,在Name2上设置XmlIgnore。然后覆盖Name并按照您喜欢的方式返回Name2的两个属性。
如果你真的需要按原样序列化那个类,那么我担心你必须使用不同的elementName。
编辑:示例代码:
public class Animal
{
[XmlElement(ElementName = "NAME")]
public virtual string Name { get; set; }
public virtual bool ShouldSerializeName() { return true; }
}
public class Cat : Animal
{
public override bool ShouldSerializeName() { return false; }
[XmlIgnore]
public NameAndType Name2 { get; set; }
[XmlElement(ElementName = "NAME")]
public override string Name
{
get
{
return String.Format("{0} [Type:{1}]", Name2.Name, Name2.Type);
}
set { }
}
}