简体   繁体   English

c# xml 反序列化为 xsi:type 值中带有冒号和连字符的对象

[英]c# xml deserialization to object with colon and hyphen in xsi:type value

I have an issue when I try to deserialize my XML File to an object using the XmlSerializer class.当我尝试使用XmlSerializer类将 XML 文件反序列化为对象时遇到问题。

My XML file looks like this:我的 XML 文件如下所示:

<fx:FIBEX xmlns:fx="http://www.asam.net/xml/fbx" xmlns:ho="http://www.asam.net/xml" xmlns:ethernet="http://www.asam.net/xml/fbx/ethernet" xmlns:it="http://www.asam.net/xml/fbx/it" xmlns:service="http://www.asam.net/xml/fbx/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="" VERSION="4.1.0">
  <fx:ELEMENTS>
    <fx:CLUSTERS>
      <fx:CLUSTER xsi:type="ethernet:CLUSTER-TYPE" ID="ID_CLUSTER_MAIN_1">
        <ho:SHORT-NAME>SomeIpDatabase</ho:SHORT-NAME>
        <fx:SPEED>1000000000</fx:SPEED>
        <fx:IS-HIGH-LOW-BIT-ORDER>false</fx:IS-HIGH-LOW-BIT-ORDER>
        <fx:BIT-COUNTING-POLICY>SAWTOOTH</fx:BIT-COUNTING-POLICY>
        <fx:PROTOCOL>ETHERNET</fx:PROTOCOL>
        <fx:PHYSICAL>OABR</fx:PHYSICAL>
        <fx:CHANNEL-REFS>
          <fx:CHANNEL-REF ID-REF="ID_CHANNEL_SOME_IP_1" />
        </fx:CHANNEL-REFS>
        <fx:MAX-FRAME-LENGTH>1500</fx:MAX-FRAME-LENGTH>
        <ethernet:MAC-MULTICAST-GROUPS>
          <ethernet:MAC-MULTICAST-GROUP ID="ID_CLUSTER_MAIN_1_ID_MACMULTICASTGROUP_SD_1">
            <ho:SHORT-NAME>SD</ho:SHORT-NAME>
            <ethernet:MAC-MULTICAST-ADDRESS>01:00:5E:40:FF:FB</ethernet:MAC-MULTICAST-ADDRESS>
          </ethernet:MAC-MULTICAST-GROUP>
          <ethernet:MAC-MULTICAST-GROUP ID="ID_CLUSTER_MAIN_1_ID_MACMULTICASTGROUP_BROADCAST_1">
            <ho:SHORT-NAME>BROADCAST</ho:SHORT-NAME>
            <ethernet:MAC-MULTICAST-ADDRESS>FF:FF:FF:FF:FF:FF</ethernet:MAC-MULTICAST-ADDRESS>
          </ethernet:MAC-MULTICAST-GROUP>
        </ethernet:MAC-MULTICAST-GROUPS>
      </fx:CLUSTER>
      <!--Additional CLUSTER elements omitted-->
    </fx:CLUSTERS>
  </fx:ELEMENTS>
  <!--PROJECT elements omitted-->
</fx:FIBEX>

When I try to deserialize the XML file now i receive the following error:当我现在尝试反序列化 XML 文件时,我收到以下错误:

System.InvalidOperationException: Error in XML-Dokument (11,5). ---> System.InvalidOperationException: The specified type was not recognized: Name='CLUSTER-TYPE', Namespace='http://www.asam.net/xml/fbx/ethernet', at <CLUSTER xmlns='http://www.asam.net/xml/fbx'>.

My deserializer class looks like this:我的解串器类如下所示:

public static T DeserializeXMLFileToObject<T>(string XmlFilename)
{
    T returnObject = default(T);
    if (string.IsNullOrEmpty(XmlFilename)) return default(T);

    try
    {
        StreamReader xmlStream = new StreamReader(XmlFilename);
        XmlSerializer serializer = new XmlSerializer(typeof(T));
        returnObject = (T)serializer.Deserialize(xmlStream);
    }
    catch (Exception ex)
    {
        Console.Write("{1} Es ist ein Fehler aufgetreten {0}", ex, DateTime.Now);
    }
    return returnObject;
}

The class that should contain the deserialized elements and attributes of the XML file looks like this:应包含 XML 文件的反序列​​化元素和属性的类如下所示:

[XmlRoot("FIBEX", Namespace = fxNameSpace)]
public class Fibextoobject
{
    [XmlElement("PROJECT", Namespace = fxNameSpace)]
    public Project project { get; set; }

    [XmlElement("ELEMENTS", Namespace = fxNameSpace)]
    public Elements elements { get; set; }

    public class Project
    {
        [XmlAttribute("OID", Namespace = hoNameSpace)]
        public string OID { get; set; }

        [XmlAttribute("ID")]
        public string ID { get; set; }

        [XmlElement("SHORT-NAME", Namespace = hoNameSpace)]
        public string shortname { get; set; }

        [XmlElement("LONG-NAME", Namespace = hoNameSpace)]
        public string longname { get; set; }
    }

    public class Elements
    {
        [XmlArray("CLUSTERS", Namespace = fxNameSpace)]
        [XmlArrayItem("CLUSTER", Namespace = fxNameSpace)]
        public List<Cluster> cluster { get; set; }

    }

    public class Cluster
    {
        [XmlAttribute("ID")]
        public string ID { get; set; }

        [XmlElement("SHORT-NAME", Namespace = hoNameSpace)]
        public string shortname { get; set; }

        [XmlElement("SPEED", Namespace = fxNameSpace)]
        public string speed { get; set; }
    }
}

How can i deserialize the XML file successfully using the xsi:type attribute with the colon and hyphen inside the value: xsi:type="ethernet:CLUSTER-TYPE" ?如何使用 xsi:type 属性和值中的冒号和连字符成功反序列化 XML 文件: xsi:type="ethernet:CLUSTER-TYPE"

Your problem is as follows.你的问题如下。 The xsi:type attribute, short for {http://www.w3.org/2001/XMLSchema-instance}type , is a w3c standard attribute that allows an element to explicitly assert its type, eg when it is a polymorphic subtype of the expected element type. xsi:type属性是{http://www.w3.org/2001/XMLSchema-instance}type缩写,是一个w3c 标准属性,它允许元素显式声明其类型,例如,当它是预期的元素类型。 XmlSerializer supports this attribute and will use it to determine the actual type of object to deserialize for such a polymorphic type. XmlSerializer支持此属性,并将使用它来确定要为此类多态类型反序列化的对象的实际类型。 However, there are several caveats and restrictions in using this attribute:但是,使用此属性有几个注意事项和限制:

  1. If xsi:type is present in the XML, then that element must be bound to a polymorphic type hierarchy.如果xsi:type存在于 XML 中,则该元素必须绑定到多态类型层次结构。 XmlSerializer will never just ignore the attribute. XmlSerializer永远不会忽略该属性。 Thus you will need to introduce a derived subtype of Cluster to deserialize this XML, eg as follows:因此,您需要引入Cluster的派生子类型来反序列化此 XML,例如:

     public class ClusterType : Cluster { }
  2. XmlSerializer requires that it be informed in advance of all possible subtypes using [XmlInclude(typeof(TDerivedType))] . XmlSerializer要求使用[XmlInclude(typeof(TDerivedType))]提前通知所有可能的子类型。 Normally one would place this attribute on the base type:通常人们会将此属性放在基本类型上:

     [XmlInclude(typeof(ClusterType))] // Add XmlInclude for all additional subtypes here. public class Cluster { // Remainder unchanged
  3. Your xsi:type value contains characters that cannot be included in ac# identifier:您的xsi:type值包含无法包含在 ac# 标识符中的字符:

     xsi:type="ethernet:CLUSTER-TYPE"

    In this case, XmlSerializer interprets the the value as a qualified name where the portion before the : is an XML namespace prefix of a valid namespace in scope, and the portion afterwards corresponds to the XmlTypeAttribute.TypeName of the polymorphic type.在这种情况下, XmlSerializer将该值解释为限定名称,其中:之前的部分是作用域中有效命名空间的 XML 命名空间前缀,后面的部分对应于多态类型的XmlTypeAttribute.TypeName You can inform the serializer of the expected namespace and type by applying the [XmlType] attribute to the derived type as follows:您可以通过将[XmlType]属性应用于派生类型来通知序列化程序预期的命名空间和类型,如下所示:

     [XmlType("CLUSTER-TYPE", Namespace = ethernetNameSpace)] public class ClusterType : Cluster { }

    Where ethernetNameSpace is defined as:其中ethernetNameSpace定义为:

     public const string ethernetNameSpace = "http://www.asam.net/xml/fbx/ethernet";
  4. For some reason XmlSerializer requires the XmlTypeAttribute.Namespace to be initialized to something on the base type if it is set to anything at all on included derived types.出于某种原因,如果XmlSerializer在包含的派生类型上设置为任何内容,XmlSerializer需要将XmlTypeAttribute.Namespace初始化为基类型上的内容 The value of the namespace doesn't seem to matter when deserializing an instance of the derived type (though obviously it would when deserializing the base type), it just needs to be set to something .在反序列化派生类型的实例时,命名空间的值似乎并不重要(尽管在反序列化基类型时很明显),它只需要设置为something Even the empty string will work, eg:即使是空字符串也能工作,例如:

     // The XmlTypeAttribute.Namespace below must be initialized to something if it is also initialized on the derived type. // However, the actual value does not need to be the same as the child's namespace, so modify to be something more appropriate // based on additional XML samples. [XmlType("CLUSTER", Namespace = "")] [XmlInclude(typeof(ClusterType))] // Add XmlInclude for all additional subtypes here. public class Cluster { // Remainder unchanged

    If the base type XML namespace is not set, XmlSerializer will throw an exception with a misleading message:如果未设置基本类型 XML 命名空间, XmlSerializer将抛出带有误导性消息的异常:

    System.InvalidOperationException: There was an error generating the XML document. System.InvalidOperationException: 生成 XML 文档时出错。 ---> System.InvalidOperationException: The type Fibextoobject+ClusterType was not expected. ---> System.InvalidOperationException: Fibextoobject+ClusterType 类型不是预期的。 Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.使用 XmlInclude 或 SoapInclude 属性指定静态未知的类型。

    Since ClusterType is in fact included via [XmlInclude] the message is not helpful.由于ClusterType实际上是通过[XmlInclude]包含的,因此该消息没有帮助。 It took a bit of experimentation to determine the actual problem.需要进行一些实验才能确定实际问题。

A working version of your Fibextoobject type which puts all of the above items into action is as follows:将上述所有项目付诸实施的Fibextoobject类型的工作版本如下:

[XmlRoot("FIBEX", Namespace = fxNameSpace)]
public partial class Fibextoobject
{
    [XmlElement("PROJECT", Namespace = fxNameSpace)]
    public Project project { get; set; }

    [XmlElement("ELEMENTS", Namespace = fxNameSpace)]
    public Elements elements { get; set; }

    public class Project
    {
        [XmlAttribute("OID", Namespace = hoNameSpace)]
        public string OID { get; set; }

        [XmlAttribute("ID")]
        public string ID { get; set; }

        [XmlElement("SHORT-NAME", Namespace = hoNameSpace)]
        public string shortname { get; set; }

        [XmlElement("LONG-NAME", Namespace = hoNameSpace)]
        public string longname { get; set; }
    }

    public class Elements
    {
        [XmlArray("CLUSTERS", Namespace = fxNameSpace)]
        [XmlArrayItem("CLUSTER", Namespace = fxNameSpace)]
        public List<Cluster> cluster { get; set; }
    }

    [XmlType("CLUSTER-TYPE", Namespace = ethernetNameSpace)]
    public class ClusterType : Cluster
    {
    }

    // The XmlTypeAttribute.Namespace below must be initialized to something if it is also initialized on the derived type.
    // However, the actual value does not need to be the same as the child's namespace, so modify to be something more appropriate
    // based on additional XML samples.
    [XmlType("CLUSTER", Namespace = "")] 
    [XmlInclude(typeof(ClusterType))]
    // Add XmlInclude for all additional subtypes here.
    public class Cluster
    {
        [XmlAttribute("ID")]
        public string ID { get; set; }

        [XmlElement("SHORT-NAME", Namespace = hoNameSpace)]
        public string shortname { get; set; }

        [XmlElement("SPEED", Namespace = fxNameSpace)]
        public string speed { get; set; }
    }
}

public partial class Fibextoobject
{
    public const string fxNameSpace = "http://www.asam.net/xml/fbx";
    public const string hoNameSpace = "http://www.asam.net/xml";
    public const string ethernetNameSpace = "http://www.asam.net/xml/fbx/ethernet";
    public const string itNameSpace = "http://www.asam.net/xml/fbx/it";
    public const string serviceNameSpace = "http://www.asam.net/xml/fbx/services";
}

Sample working Roslyn .Net fiddle .示例工作Roslyn .Net fiddle

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM