[英]c# xml deserialization to object with colon and hyphen in xsi:type value
当我尝试使用XmlSerializer
类将 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'>.
我的解串器类如下所示:
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 文件的反序列化元素和属性的类如下所示:
[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 标准属性,它允许元素显式声明其类型,例如,当它是预期的元素类型。 XmlSerializer
支持此属性,并将使用它来确定要为此类多态类型反序列化的对象的实际类型。 但是,使用此属性有几个注意事项和限制:
如果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
值包含无法包含在 ac# 标识符中的字符:
xsi:type="ethernet:CLUSTER-TYPE"
在这种情况下, XmlSerializer
将该值解释为限定名称,其中:
之前的部分是作用域中有效命名空间的 XML 命名空间前缀,后面的部分对应于多态类型的XmlTypeAttribute.TypeName
。 您可以通过将[XmlType]
属性应用于派生类型来通知序列化程序预期的命名空间和类型,如下所示:
[XmlType("CLUSTER-TYPE", Namespace = ethernetNameSpace)] public class ClusterType : Cluster { }
其中ethernetNameSpace
定义为:
public const string ethernetNameSpace = "http://www.asam.net/xml/fbx/ethernet";
出于某种原因,如果XmlSerializer
在包含的派生类型上设置为任何内容,则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: 生成 XML 文档时出错。 ---> System.InvalidOperationException: Fibextoobject+ClusterType 类型不是预期的。 使用 XmlInclude 或 SoapInclude 属性指定静态未知的类型。
由于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 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.