c# xml 反序列化到 xsi:type 值中带有冒号和连字符的对象
c# xml deserialization to object with colon and hyphen in xsi:type value
当我尝试使用 XmlSerializer
class.
将我的 XML 文件反序列化为对象时遇到问题
我的 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 文件时,我收到以下错误:
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'>.
我的反序列化器 class 看起来像这样:
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 文件的反序列化元素和属性的 class 如下所示:
[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 属性成功反序列化 XML 文件,值中包含冒号和连字符:xsi:type="ethernet:CLUSTER-TYPE"
?
您的问题如下。 xsi:type
属性是 {http://www.w3.org/2001/XMLSchema-instance}type
的缩写,是一个 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 并且将使用它来确定对象的实际类型以反序列化这种多态类型。但是,使用此属性有几个注意事项和限制:
如果 xsi:type
出现在 XML 中,则该元素 必须 绑定到多态类型层次结构。 XmlSerializer
永远不会忽略该属性。因此,您需要引入 Cluster
的派生子类型来反序列化此 XML,例如如下:
public class ClusterType : Cluster
{
}
XmlSerializer
要求使用[XmlInclude(typeof(TDerivedType))]
提前通知 所有可能的子类型。通常将此属性放在基本类型上:
[XmlInclude(typeof(ClusterType))]
// Add XmlInclude for all additional subtypes here.
public class Cluster
{
// Remainder unchanged
您的 xsi:type
值包含不能包含在 c# 标识符中的字符:
xsi:type="ethernet:CLUSTER-TYPE"
在这种情况下,XmlSerializer
将值解释为派生类型的 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]
属性,如下所示:
[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。即使是空字符串也可以,例如:
// 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
将抛出异常并显示误导性消息:
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]
包含的,因此该消息没有帮助。需要一些实验才能确定实际问题。
您的 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";
}
工作示例 Roslyn .Net fiddle。
当我尝试使用 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 文件时,我收到以下错误:
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'>.
我的反序列化器 class 看起来像这样:
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 文件的反序列化元素和属性的 class 如下所示:
[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 属性成功反序列化 XML 文件,值中包含冒号和连字符:xsi:type="ethernet:CLUSTER-TYPE"
?
您的问题如下。 xsi:type
属性是 {http://www.w3.org/2001/XMLSchema-instance}type
的缩写,是一个 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 并且将使用它来确定对象的实际类型以反序列化这种多态类型。但是,使用此属性有几个注意事项和限制:
如果
xsi:type
出现在 XML 中,则该元素 必须 绑定到多态类型层次结构。XmlSerializer
永远不会忽略该属性。因此,您需要引入Cluster
的派生子类型来反序列化此 XML,例如如下:public class ClusterType : Cluster { }
XmlSerializer
要求使用[XmlInclude(typeof(TDerivedType))]
提前通知 所有可能的子类型。通常将此属性放在基本类型上:[XmlInclude(typeof(ClusterType))] // Add XmlInclude for all additional subtypes here. public class Cluster { // Remainder unchanged
您的
xsi:type
值包含不能包含在 c# 标识符中的字符:xsi:type="ethernet:CLUSTER-TYPE"
在这种情况下,
XmlSerializer
将值解释为派生类型的 qualified name where the portion before the:
is an XML namespace prefix of a valid namespace in scope, and the portion afterwards corresponds to theXmlTypeAttribute.TypeName
of the polymorphic type. You can inform the serializer of the expected namespace and type by applying the[XmlType]
属性,如下所示:[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。即使是空字符串也可以,例如:// 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
将抛出异常并显示误导性消息: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]
包含的,因此该消息没有帮助。需要一些实验才能确定实际问题。
您的 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";
}
工作示例 Roslyn .Net fiddle。