使用 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】:

看来你这里是:

    &lt;nameServers&gt;,其中 &lt;hostNames&gt;,其中 &lt;Address&gt; 的数组,其中 纯文本

你想把它映射到:

    WhoisRecordNameServersV2,其中 hostNames,其中 AddressWrapper 的数组,其中 Address: string

看到平行线了吗?对我来说,这看起来像是一个幸运的一对一映射:

    &lt;nameServers&gt; 映射到 WhoisRecordNameServersV2 &lt;hostNames&gt; 映射到 hostNames &lt;Address&gt; 映射到 AddressWrapper &lt;Address&gt; 中的纯文本映射到AddressWrapper 中的Address

现在您需要做的就是正确注释类型和字段:

    WhoisRecordNameServersV2 映射到 &lt;nameServers&gt;,所以它需要 XmlType("nameServers") hostNames 映射到 &lt;hostNames&gt; 并包含一个数组,因此它需要 XmlArray("hostNames") AddressWrapper 映射到&lt;Address&gt;,所以它需要XmlType("Address") Address inside AddressWrapper 映射到 &lt;Address&gt; 内的纯文本,所以它需要XmlText

把它们放在一起:

[<CLIMutable; XmlType("Address")>]
type AddressWrapper =
     [<XmlText>] Address: string 

[<CLIMutable; XmlType("nameServers")>]
type WhoisRecordNameServersV2 =
     [<XmlArray("hostNames")>] hostNames: AddressWrapper [] 

【讨论】:

啊,太好了,非常感谢。映射不是我的问题,但我一直不知道XmlText!在地址中使用它可以解决问题。工作型号:type Address = [&lt;XmlText&gt;] Address: string

以上是关于使用 C# 代码和 F# 模型的 XML 反序列化的主要内容,如果未能解决你的问题,请参考以下文章

创建 C# 模型以反序列化 XML 提要

C# 将 XML 反序列化为模型类错误 - <xmlns=""> 不是预期的

C# 使用多个可能的命名空间反序列化 xml

使用 SOAP 请求 C# 的 XML 序列化和反序列化

使用 C# Xml.Serialization 库反序列化每个重复的 XML 节点并将其映射到对象的属性

需要帮助将 XML 文件反序列化为对象 C#