FSharp.Data类型提供程序和反射:如何检查XmlProvider类型的属性?

3
我正在尝试使用XmlProvider来解析一些非常大的数据文件(约50 MB)。由于它们非常大,因此不实用将真实数据文件用作样本,因此我已经创建了一个带有我所希望的可用数据的代表性XML文件。然而,我并不100%确定我已经涵盖了该50兆字节文件中的所有可能元素,因此我正在尝试验证我的样本是否具有代表性。我正在尝试使用反射来帮助进行验证,但我遇到了问题。
首先,背景。我不确定的原因是因为我正在解析的XML文件具有以下(非常平坦)数据结构:
<root-element>
<object class="Foo" guid="Guid001">
    <color>Brown</color>
    <shape>Square</shape>
    <children>
        <childRef guid="Guid003" />
    </children>
</object>
<object class="Bar" guid="Guid002">
    <firstName>John</firstName>
    <lastName>Smith</lastName>
</object>
<object class="Quux" guid="Guid003" parentGuid="Guid001">
    <secondaryColor>Maroon</secondaryColor>
    <stroke>Dashed</stroke>
    <shape>Circle</shape>
</object>
<object class="Quux" guid="Guid004">
    <color>Blue</color>
    <stroke>Dotted</stroke>
    <shape>Hexagon</shape>
</object>
</root-element>

在真实的数据文件中,“Guid001”等都是真正的GUID;但为了这个虚构的例子,我保持了它们的简单性。基本上,这是一个扁平的数据文件,有很多object元素,每个元素对应于程序中的C#类实例。这些元素被半随机地混合在一起,同一个数据文件中表示几个不同的类族。(这就是为什么我的虚构数据文件将绘图形状与人员记录混合在一起的原因——我正在处理的真实数据文件在一个文件中具有类似的混合关注点。)就像我说的那样,我随机选择了一堆记录作为我的代表样本。我尽量从每个类中挑选至少一个,以便涵盖大部分属性名称,但如果(例如)我选择了Quux类的Guid004而不是Guid003怎么办?那么我的提供的类型实际上将不知道SecondaryColor属性。我想我可以在提供的类型上使用.GetType(),然后调用.GetProperties()来获取提供的类型认为自己知道的所有属性的列表。但当我这样做时:
let firstObject = rootElement.Objects[0]
printfn "%A" firstObject.GetType().GetProperties()

我原本期望得到的是一个名为ColorShapeChildrenFirstName等属性的列表,但实际上我只得到了两个属性:XElement_Print

我可以遍历真实数据中的所有XElement,并组合它们的子元素名称。然后从我的示例数据中获取子元素名称的集合,并比较这两个集合。如果两个集合相等(例如它们之间的差集为空集),那么我就知道在示例数据中已经涵盖了所有情况。

然而,我正在使用XmlProvider,正是因为我不想处理XElement及其怪癖(例如到处都是XName而不是字符串等)。我知道可以检索XmlProvider提供的类型的有效属性列表,因为Atom中的自动完成下拉菜单(通过Ionide)正是给了我这个列表:所有有效属性的列表。但是,当应用于XmlProvider提供的类型时,标准的.Net反射方法似乎没有做我期望的事情。所以,既然反射似乎没有做我期望的事情,那么我应该怎么做才能获得XmlProvider为我的类型创建的有效属性列表呢?
1个回答

6
XML类型提供程序是一种擦除类型提供程序,表示XML元素的所有对象在编译代码中成为同一类型的值,称为FSharp.Data.Runtime.BaseTypes.XmlElement。所提供的属性被擦除,并被替换为通过名称查找访问属性值的代码片段。
这意味着反射将永远无法看到所提供的属性。获取它们的唯一方法是访问底层的XElement并直接使用它。例如,要获取子元素,可以编写以下代码:
[ for e in firstObject.XElement.Elements() -> e.Name.LocalName ]

在您提供的示例中,这将返回一个包含["color"; "shape"; "children"]的列表。


1
谢谢。虽然这显然不是我想要的答案,但这是我需要的答案,因为现在我将停止寻找基于反射的解决方案,直接使用 XElement - rmunn
另外,感谢您提醒我关于[ for item in sequence -> value ]语法的存在。我已经忘记了它的存在,并一直在使用更冗长的[ for item in sequence do yield value ]等价语法。对于这种常见用例来说,更短的语法绝对更好。 - rmunn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接