C# XML序列化彼此内部的元素
我有一个可以自己序列化的类,例如:C# XML序列化彼此内部的元素,c#,.net,xml,generics,serialization,C#,.net,Xml,Generics,Serialization,我有一个可以自己序列化的类,例如: [XmlRoot("NameOfMyRoot", Namespace = "myNamespace")] public class Inner { public Inner(){} public string SomeString { get; set; } } 这是一个完美的序列化(我正在为myNamespace使用ns别名,请参阅完整演示) 现在我希望此对象成为另一个对象(包装器)的一部分: [XmlRoot(“根”)] 公共舱外 {
[XmlRoot("NameOfMyRoot", Namespace = "myNamespace")]
public class Inner
{
public Inner(){}
public string SomeString { get; set; }
}
这是一个完美的序列化(我正在为myNamespace
使用ns
别名,请参阅完整演示)
现在我希望此对象成为另一个对象(包装器)的一部分:
[XmlRoot(“根”)]
公共舱外
{
公共T属性{get;set;}
公共外部(){}
公共外部(T内部)
{
属性=内部;
}
}
这就给了我:
<?xml version="1.0" encoding="utf-16"?>
<Root xmlns:ns="myNamespace">
<Property>
<ns:SomeString></ns:SomeString>
</Property>
</Root>
我想要的只是将内部对象按原样嵌入其父对象,如下所示:
<?xml version="1.0" encoding="utf-16"?>
<Root>
<NameOfMyRoot xmlns:ns="myNamespace">
<ns:SomeString></ns:SomeString>
</NameOfMyRoot>
</Root>
请注意,名称空间不应移动到根,并且我不能指定元素的名称,因为将有许多不同的类型。
.
当然,我可以将它们单独序列化,然后通过一些讨厌的字符串操作进行组合,但我希望有一种巧妙的方法来实现这一点。实现这一点并不容易。不过,您可以在运行时执行此操作:
// perhaps discover these details at runtime
var attribs = new XmlAttributeOverrides();
attribs.Add(typeof(Outer<Inner>), "Property", new XmlAttributes
{
XmlElements = { new XmlElementAttribute {ElementName = "NameOfMyRoot" } }
});
attribs.Add(typeof(Inner), "SomeString", new XmlAttributes
{
XmlElements = { new XmlElementAttribute { Namespace = "myNamespace"} }
});
var ser = new XmlSerializer(typeof(Outer<Inner>), attribs);
var obj = new Outer<Inner> { Property = new Inner { SomeString = "abc" } };
ser.Serialize(Console.Out, obj);
如果您不需要这两个xmlns
别名声明,则可以分别删除它们,但它们不会改变其含义,至少对于兼容的读取器是如此。同样,可以将ns
添加为别名:
var obj = new Outer<Inner> { Property = new Inner { SomeString = "abc" } };
var ns = new XmlSerializerNamespaces();
ns.Add("", "");
ns.Add("ns", "myNamespace");
ser.Serialize(Console.Out, obj, ns);
我在这里所做的是手动编写根节点,只让XmlSerializer
编写内部内容。请注意,我必须更改SomeString的属性,以使其以您期望的方式工作(其中是具有名称空间的字符串,而不是对象)。没有简单的方法可以做到这一点。不过,您可以在运行时执行此操作:
// perhaps discover these details at runtime
var attribs = new XmlAttributeOverrides();
attribs.Add(typeof(Outer<Inner>), "Property", new XmlAttributes
{
XmlElements = { new XmlElementAttribute {ElementName = "NameOfMyRoot" } }
});
attribs.Add(typeof(Inner), "SomeString", new XmlAttributes
{
XmlElements = { new XmlElementAttribute { Namespace = "myNamespace"} }
});
var ser = new XmlSerializer(typeof(Outer<Inner>), attribs);
var obj = new Outer<Inner> { Property = new Inner { SomeString = "abc" } };
ser.Serialize(Console.Out, obj);
如果您不需要这两个xmlns
别名声明,则可以分别删除它们,但它们不会改变其含义,至少对于兼容的读取器是如此。同样,可以将ns
添加为别名:
var obj = new Outer<Inner> { Property = new Inner { SomeString = "abc" } };
var ns = new XmlSerializerNamespaces();
ns.Add("", "");
ns.Add("ns", "myNamespace");
ser.Serialize(Console.Out, obj, ns);
我在这里所做的是手动编写根节点,只让
XmlSerializer
编写内部内容。请注意,我必须更改SomeString
周围的属性,以使其以您期望的方式工作(其中是具有名称空间的字符串,而不是对象)。注意:问题看起来不一致;[XmlRoot(“NameOfMyRoot”,Namespace=“myNamespace”)]公共类内部{…}
的xml不是
,而是
——这是一个巨大的问题difference@MarcGravell同意。补充说明:问题看起来不一致;[XmlRoot(“NameOfMyRoot”,Namespace=“myNamespace”)]公共类内部{…}
的xml不是
,而是
——这是一个巨大的问题difference@MarcGravell同意。我需要在内部类本身上设置名称空间(就像在类的声明中一样)。既不在SomeString
上,也不在Root
上。至于元素的名称替换,这很好。@MaximGrishin这是一个名称空间别名声明,而不是名称空间;它在两个级别上都同样有效——别名是继承的,不会更改声明元素的语义。如果您的意思是NameOfMyRoot
应该在myNamespace
名称空间中:这不是您的示例所显示的。我很乐意调整我的代码以适应-我编写的代码适合你的例子。@MaximGrishin具体来说,当你说“我想要的只是将内部对象按原样嵌入其父对象,如:
-在该代码中,NameOfMyRoot
位于空/默认命名空间中,而不是myNamespace
命名空间。是的,抱歉,我的意思是名称空间别名声明应该属于NameOfMyRoot
元素。@MaximGrishin不直接支持,但无论名称空间别名声明位于何处,数据的含义都是相同的(或者即使它有别名,也可以使用显式名称空间语法)。我可以问一下为什么需要移动名称空间别名吗?因为它使事情变得非常复杂……我需要在内部类本身上设置名称空间(就像在类的声明中一样)。既不在SomeString
上,也不在Root
上。至于元素的名称替换,这很好。@MaximGrishin这是一个名称空间别名声明,而不是名称空间;它在两个级别上都同样有效——别名是继承的,不会更改声明元素的语义。如果您的意思是NameOfMyRoot
应该在myNamespace
名称空间中:这不是您的示例所显示的。我很乐意调整我的代码以适应-我编写的代码适合你的例子。@MaximGrishin具体来说,当你说“我想要的只是将内部对象按原样嵌入其父对象,如:
-在该代码中,NameOfMyRoot
位于空/默认命名空间中,而不是myNamespace
命名空间。是的,抱歉,我的意思是名称空间别名声明应该属于NameOfMyRoot
元素。@MaximGrishin不直接支持,但无论名称空间别名声明位于何处,数据的含义都是相同的(或者即使它有别名,也可以使用显式名称空间语法)。我可以问一下为什么需要移动名称空间别名吗?因为这会使事情变得复杂。。。
var obj = new Outer<Inner> { Property = new Inner { SomeString = "abc" } };
var ns = new XmlSerializerNamespaces();
ns.Add("", "");
ns.Add("ns", "myNamespace");
ser.Serialize(Console.Out, obj, ns);
<Root xmlns:ns="myNamespace">
<NameOfMyRoot>
<ns:SomeString>abc</ns:SomeString>
</NameOfMyRoot>
</Root>
using System;
using System.Xml;
using System.Xml.Serialization;
[XmlRoot("NameOfMyRoot")]
public class Inner
{
public Inner() { }
[XmlElement(Namespace = "myNamespace")]
public string SomeString { get; set; }
}
static class Program
{
static void Main()
{
using (XmlWriter writer = XmlWriter.Create(Console.Out))
{
writer.WriteStartDocument(false);
writer.WriteStartElement("Root");
var ser = new XmlSerializer(typeof(Inner));
var obj = new Inner { SomeString = "abc" };
var ns = new XmlSerializerNamespaces();
ns.Add("", "");
ns.Add("ns", "myNamespace");
ser.Serialize(writer, obj, ns);
writer.WriteEndElement();
writer.WriteEndDocument();
}
}
}