XmlSerializer 将 xsi:type 替换为节点名称

发布于 2025-01-07 10:35:14 字数 322 浏览 2 评论 0原文

目前 XmlSerializer 生成以下结构:

<config>
  <BaseType xsi:type="DerivedType1" />
  <BaseType xsi:type="DerivedType2" />
</config>

有没有办法让它将类型名称放入节点:

<config>
  <DerivedType1 />
  <DerivedType2 />
</config>

Currently XmlSerializer produces the following structure:

<config>
  <BaseType xsi:type="DerivedType1" />
  <BaseType xsi:type="DerivedType2" />
</config>

Is there any way to make it put type name into node:

<config>
  <DerivedType1 />
  <DerivedType2 />
</config>

?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

高速公鹿 2025-01-14 10:35:14

使用 XmlElementAttribute 构造函数重载 (string elementName, Type type)
它允许您根据成员中找到的实际类型替换元素名称。
如果您有多个派生类型,请将其中几个堆叠在一起。

如果您尝试序列化可能包含 Derived 实例的 List 等通用集合,则以相同的方式使用 XmlArrayItem

以这种方式定义也隐式地使派生类型已知,因此不需要 XmlInclude 属性

示例定义:

[XmlRoot]
public class Data
{
    [XmlElement("Derived1", typeof(Derived1))]
    [XmlElement("Derived2", typeof(Derived2))]
    public Base foo { get; set; }
    [XmlArrayItem("Derived1", typeof(Derived1))]
    [XmlArrayItem("Derived2", typeof(Derived2))]
    public List<Base> fooList { get; set; }
}

public class Base { ... }
public class Derived1 : Base { ... }
public class Derived2 : Base { ... }

Use the XmlElementAttribute constructor overload (string elementName, Type type).
It allows you to replace the element name given the actual type found in the member.
Stack several of these together if you have multiple derived types.

If you are trying to serialize a generic collection like List<Base> that might contain instances of Derived then use the XmlArrayItem in the same way.

Defining in this way also implicitly makes the derived type known, So an XmlInclude attribute is not required

Sample definition:

[XmlRoot]
public class Data
{
    [XmlElement("Derived1", typeof(Derived1))]
    [XmlElement("Derived2", typeof(Derived2))]
    public Base foo { get; set; }
    [XmlArrayItem("Derived1", typeof(Derived1))]
    [XmlArrayItem("Derived2", typeof(Derived2))]
    public List<Base> fooList { get; set; }
}

public class Base { ... }
public class Derived1 : Base { ... }
public class Derived2 : Base { ... }
Saygoodbye 2025-01-14 10:35:14

为什么人们总是说“你永远无法反序列化”。
这绝对是错误的。

public class BaseClass {
  public string Name {get;set;}
}
[XmlRoot("BaseClass")]
public class ChildClass : BaseClass {
  public int Value {get;set;}
}
[XmlRoot("BaseClass")]
public class FlatClass
{
  public string Name {get;set;}
  public int Value {get;set;}
}

XmlSerializer ser1 = new XmlSerializer(typeof(BaseClass));
XmlSerializer ser2 = new XmlSerializer(typeof(ChildClass));
XmlSerializer ser3 = new XmlSerializer(typeof(FlatClass));
ser1.Serialize(File.Open("ser1.xml", FileMode.Create), new BaseClass(){Name="Base"});
ser2.Serialize(File.Open("ser2.xml", FileMode.Create), new ChildClass(){Name="Child",Value = 1});

ser1.Deserialize(File.OpenRead("ser2.xml"));
ser2.Deserialize(File.OpenRead("ser1.xml"));
ser3.Deserialize(File.OpenRead("ser2.xml"));

繁荣。工作得很好!!!!
序列化完美地实现了这三种方式。生成的对象可能不是 100%,但它确实会反序列化。
反序列化 ser2.xml 时 Ser1 忽略 Value 元素
反序列化 ser1.xml 时,Ser2 SKIPS the Value property

唯一破坏此模型的是:

ser1.Serailize(File.Open("ser3.xml", FileMode.Create), new ChildClass(){Name = "Child2", Value = 2});
XmlSerialize ser3 = new XmlSerializer(typeof(FlatClass));
ser3.Deserialize(File.OpenRead("ser3.xml"));

最后一个破坏,因为 BaseClass 的序列化程序遵循模式标准(尽管这是一个有价值的且 99% 的时间都需要的标准),其中包括元素上的 xsi:type="ChildClass" 属性。 Ser3 无法处理该类型,因为它与该类型无关,特别是当 FlatClass 存在于跨 WAN 或 LAN 线路的另一个程序集中时。
就像 Honey-badger 一样,XmlSerailizer 不关心元素或值,只要它能找到它们并且架构中没有任何内容会破坏该过程。 XSI:TYPE 属性破坏了架构。

例如,当使用 WCF 或其他基于 XML 通信的系统时,如果服务有一个名为 FlatClass 的类,则它不会反序列化包含 xsi:type="" 属性的 ChildClass。但是,如果您不使用 BaseClass 的序列化程序,它将反序列化完全相同的 XML,而无需 xsi:type 属性。

量子电动力学
包含 xsi:type 属性通常是有益的、必要的和可取的。

那么,是否有一种方法可以为 BaseClass 类型创建 XmlSerializer,并告诉它在序列化子类型时不要包含 xsi:type 属性?

谢谢
杰登·“西弗·迪亚斯”·拉克·毁灭者

Why do people keep saying "you'll never be able to deserialize."
That is definitionally FALSE.

public class BaseClass {
  public string Name {get;set;}
}
[XmlRoot("BaseClass")]
public class ChildClass : BaseClass {
  public int Value {get;set;}
}
[XmlRoot("BaseClass")]
public class FlatClass
{
  public string Name {get;set;}
  public int Value {get;set;}
}

XmlSerializer ser1 = new XmlSerializer(typeof(BaseClass));
XmlSerializer ser2 = new XmlSerializer(typeof(ChildClass));
XmlSerializer ser3 = new XmlSerializer(typeof(FlatClass));
ser1.Serialize(File.Open("ser1.xml", FileMode.Create), new BaseClass(){Name="Base"});
ser2.Serialize(File.Open("ser2.xml", FileMode.Create), new ChildClass(){Name="Child",Value = 1});

ser1.Deserialize(File.OpenRead("ser2.xml"));
ser2.Deserialize(File.OpenRead("ser1.xml"));
ser3.Deserialize(File.OpenRead("ser2.xml"));

Boom. Works just FINE!!!!!
Serialization goes all three both ways perfectly. the resulting objects may not be 100% on either side, but it DOES deserialize.
Ser1 IGNORES the Value element when deserializing ser2.xml
Ser2 SKIPS the Value propertuy when deserializing ser1.xml

The only thing that breaks this model is:

ser1.Serailize(File.Open("ser3.xml", FileMode.Create), new ChildClass(){Name = "Child2", Value = 2});
XmlSerialize ser3 = new XmlSerializer(typeof(FlatClass));
ser3.Deserialize(File.OpenRead("ser3.xml"));

This last breaks, becuase the the Serializer for the BaseClass follows the schema standard (albeit a valuable and 99% of the time desired standard) of including the xsi:type="ChildClass" attribute on the element. Ser3 cannot process that type because it is not realated to that type, especially if FlatClass exists in another assembly across WAN or LAN lines.
Just like the Honey-badger the XmlSerailizer DON'T CARE about the elements or values as long as it can find them and nothing in the schema breaks the process. The XSI:TYPE attribute breaks the schema.

Like, for instance, when using WCF or other XML communication based systems if the Service has a class called FlatClass, it WILL NOT DESERIALIZE a ChildClass that contains the xsi:type="" attribute. However, if you don't use the serializer for the BaseClass, it WILL deserialize the exact same XML without that xsi:type attribute.

Q.E.D.
It is often times beneficial, necessary, and DESIRABLE, to NOT include the xsi:type attribute.

So with that being said is there a way to have an XmlSerializer created for the BaseClass type and tell it NOT to include the xsi:type attribute when serializing a child type?

Thanks
Jaeden "Sifo Dyas" al'Raec Ruiner

他是夢罘是命 2025-01-14 10:35:14

好吧,您可以使用 XmlElement 属性覆盖元素名称,例如

[XmlElement("DerivedType1")]
public BaseType : DerivedType1 {get;set;}

,如果仍然将 xsi:type 放入其中,则会产生更大的混乱...

您的类是什么样的?

Well you can just override the element name with the XmlElement Attrribute e.g.

[XmlElement("DerivedType1")]
public BaseType : DerivedType1 {get;set;}

if will still put the xsi:type in though, and generate even greater confusion...

What does your class look like?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文