c#xml反序列化到xsi:type值中带有冒号和连字符的对象 [英] c# xml deserialization to object with colon and hyphen in xsi:type value

查看:568
本文介绍了c#xml反序列化到xsi:type值中带有冒号和连字符的对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我尝试使用 XmlSerializer 类将XML文件反序列化为对象时遇到问题。

I have an issue when I try to deserialize my XML File to an object using the XmlSerializer class.

我的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>

当我现在尝试反序列化XML文件时,出现以下错误:

When I try to deserialize the XML file now i receive the following error:

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;
}

应包含反序列化的XML文件的元素和属性的类如下

The class that should contain the deserialized elements and attributes of the XML file looks like this:

[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; }
    }
}

如何使用xsi:type属性,值中包含冒号和连字符: xsi:type = ethernet:CLUSTER-TYPE

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 属性,是 {http://www.w3.org/2001/XMLSchema-instance} type w3c标准属性,它允许元素明确声明它的类型,例如当它是预期元素类型的多态子类型时。 XmlSerializer 支持此属性,并将使用它来确定要反序列化为此类多态类型的对象的实际类型。但是,使用此属性存在一些警告和限制:

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, e.g. when it is a polymorphic subtype of the expected element type. XmlSerializer supports this attribute and will use it to determine the actual type of object to deserialize for such a polymorphic type. However, there are several caveats and restrictions in using this attribute:


  1. 如果 xsi:type 存在于XML中,然后该元素必须绑定到多态类型层次结构。 XmlSerializer 永远不会忽略该属性。因此,您将需要引入 Cluster 的派生子类型来反序列化此XML,例如如下:

  1. If xsi:type is present in the XML, then that element must be bound to a polymorphic type hierarchy. XmlSerializer will never just ignore the attribute. Thus you will need to introduce a derived subtype of Cluster to deserialize this XML, e.g. as follows:

public class ClusterType : Cluster
{
}


  • XmlSerializer 要求提前通知 rel = nofollow noreferrer> [XmlInclude(typeof(TDerivedType))] 。通常,将这个属性放在基本类型上:

  • XmlSerializer requires that it be informed in advance of all possible subtypes using [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
    


  • 您的 xsi:type 值包含ac#标识符中不能包含的字符:

  • Your xsi:type value contains characters that cannot be included in a c# identifier:

    xsi:type="ethernet:CLUSTER-TYPE"
    

    在这种情况下, XmlSerializer 将该值解释为限定名称,其中之前的部分是作用域中有效名称空间的XML名称空间前缀,之后的部分对应于 XmlTypeAttribute.TypeName 多态类型。您可以通过应用 [XmlType] 属性的派生类型如下:

    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. You can inform the serializer of the expected namespace and type by applying the [XmlType] attribute to the derived type as follows:

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

    其中 ethernetNameSpace 的定义为:

    public const string ethernetNameSpace = "http://www.asam.net/xml/fbx/ethernet";
    


  • 由于某些原因 XmlSerializer 要求 XmlTypeAttribute.Namespace 初始化为基本类型上的某个内容(如果在包含的派生类型上将其设置为任何内容)。在反序列化派生类型的实例时,名称空间的值似乎无关紧要(尽管显然在反序列化基本类型时会如此),只需将其设置为 something 。甚至空字符串也可以使用,例如:

  • 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. 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. Even the empty string will work, e.g.:

    // 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
    

    如果如果未设置基本类型的XML命名空间,则 XmlSerializer 会引发具有误导性消息的异常:

    If the base type XML namespace is not set, XmlSerializer will throw an exception with a misleading message:


    System.InvalidOperationException:生成XML文档时出错。 ---> System.InvalidOperationException:预计类型为Fibextoobject + ClusterType。使用XmlInclude或SoapInclude属性可以指定静态未知的类型。

    System.InvalidOperationException: There was an error generating the XML document. ---> System.InvalidOperationException: The type Fibextoobject+ClusterType was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.

    由于 ClusterType [XmlInclude] 包含了$ c,该消息没有帮助。经过一些实验才能确定实际问题。

    Since ClusterType is in fact included via [XmlInclude] the message is not helpful. It took a bit of experimentation to determine the actual problem.

    工作版本您的 Fibextoobject 类型将上述所有内容都付诸实施,如下所示:

    A working version of your Fibextoobject type which puts all of the above items into action is as follows:

    [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";
    }
    

    示例工作罗斯林.Net小提琴

    这篇关于c#xml反序列化到xsi:type值中带有冒号和连字符的对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆