使用 C# 代码和 F# 模型的 XML 反序列化
Posted
技术标签:
【中文标题】使用 C# 代码和 F# 模型的 XML 反序列化【英文标题】:XML deserialization using C# code and F# models 【发布时间】:2021-10-13 07:55:03 【问题描述】:我有这个不寻常的要求,将一些模型从 C# 迁移到 F#,老实说,我在 XML 反序列化方面有点挣扎。这是我到目前为止所拥有的。以下 XML + 反序列化 C# 代码 + F# 模型的组合完美运行:
<nameServers>
<hostNames>
<AddressWrapper>
<Address>www.blah1.com</Address>
</AddressWrapper>
<AddressWrapper>
<Address>www.blah2.com</Address>
</AddressWrapper>
</hostNames>
</nameServers>
[<CLIMutable>]
[<XmlTypeAttribute("AddressWrapper")>]
type AddressWrapper =
[<XmlElement("Address")>]
Address: string
[<CLIMutable>]
type WhoisRecordNameServersV2 =
[<XmlArray("hostNames")>]
hostNames: AddressWrapper []
以下只是一个草稿,不要对代码附加任何意义:
var xmlResponse = await File.ReadAllTextAsync(xmlResponsePath);
var stream = new MemoryStream(Encoding.UTF8.GetBytes(xmlResponse));
using var xmlReader = new XmlTextReader(stream) XmlResolver = null;
var serializer = new XmlSerializer(typeof(WhoisServiceExternal.WhoisRecordV2));
var record = serializer.Deserialize(xmlReader) as WhoisServiceExternal.WhoisRecordV2;
并且record
确实可以正确创建并填充其属性。但是,该 XML 并不是我真正想要反序列化的。我真正想要的是:
<nameServers>
<hostNames>
<Address>ns1.google.com</Address>
<Address>ns2.google.com</Address>
</hostNames>
</nameServers>
我的问题是:如何调整我的 F# 模型,以便正确反序列化第二段 XML?
我觉得问这种微不足道的问题很傻,但我觉得我已经尝试了太多模型属性、不同属性和名称的配置,但似乎没有任何效果 - Address
字段的集合没有正确反序列化。我看到的是一个空的 hostNames
集合或空白的 Address
属性。
我一定遗漏了一些明显的东西。
更新:
感谢您回答 Fyodor。以下是我未修剪的 XML 和工作模型:
[<CLIMutable; XmlType("Address")>]
type Address =
[<XmlText>]
Address: string
[<CLIMutable>]
type WhoisRecordNameServersV2 =
rawText: string
[<XmlArray("hostNames")>]
hostNames: Address []
<nameServers>
<rawText>ns1.google.com
ns3.google.com
ns2.google.com
ns4.google.com
</rawText>
<hostNames>
<Address>ns1.google.com</Address>
<Address>ns2.google.com</Address>
</hostNames>
<ips/>
</nameServers>
【问题讨论】:
【参考方案1】:看来你这里是:
<nameServers>
,其中
<hostNames>
,其中
<Address>
的数组,其中
纯文本
你想把它映射到:
WhoisRecordNameServersV2
,其中
hostNames
,其中
AddressWrapper
的数组,其中
Address: string
看到平行线了吗?对我来说,这看起来像是一个幸运的一对一映射:
<nameServers>
映射到 WhoisRecordNameServersV2
<hostNames>
映射到 hostNames
<Address>
映射到 AddressWrapper
<Address>
中的纯文本映射到AddressWrapper
中的Address
。
现在您需要做的就是正确注释类型和字段:
WhoisRecordNameServersV2
映射到 <nameServers>
,所以它需要 XmlType("nameServers")
hostNames
映射到 <hostNames>
并包含一个数组,因此它需要 XmlArray("hostNames")
AddressWrapper
映射到<Address>
,所以它需要XmlType("Address")
Address
inside AddressWrapper
映射到 <Address>
内的纯文本,所以它需要XmlText
。
把它们放在一起:
[<CLIMutable; XmlType("Address")>]
type AddressWrapper =
[<XmlText>] Address: string
[<CLIMutable; XmlType("nameServers")>]
type WhoisRecordNameServersV2 =
[<XmlArray("hostNames")>] hostNames: AddressWrapper []
【讨论】:
啊,太好了,非常感谢。映射不是我的问题,但我一直不知道XmlText
!在地址中使用它可以解决问题。工作型号:type Address = [<XmlText>] Address: string
以上是关于使用 C# 代码和 F# 模型的 XML 反序列化的主要内容,如果未能解决你的问题,请参考以下文章
C# 将 XML 反序列化为模型类错误 - <xmlns=""> 不是预期的