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

rmu*_*unn 3 xml f# type-providers

我正在尝试使用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>
Run Code Online (Sandbox Code Playgroud)

(在真实数据文件中,"Guid001"等是真正的GUID;但对于这个虚构的例子,我保持简单.)

基本上,它是一个包含大量object元素的平面数据文件,每个元素都来自该数据来自的程序中的C#类实例.元素半随机混合在一起,在同一数据文件中表示几个不同的类族.(这就是我的虚构数据文件将绘图形状与人物记录混合的原因 - 我正在使用的真实数据文件在单个文件中具有类似的关注点.)

正如我所说,我为我的代表性样本或多或少随机选择了一堆记录.我试图从每个班级中挑选至少一个,这样我就可以覆盖大部分属性名称,但是如果(例如)我最终选择Guid004用于Quux类而不是Guid003?然后我提供的类型实际上不知道该SecondaryColor属性.我想我可以.GetType()在我提供的类型上使用,然后调用.GetProperties()以获取我提供的类型认为它知道的所有属性的列表.但是当我这样做时:

let firstObject = rootElement.Objects[0]
printfn "%A" firstObject.GetType().GetProperties()
Run Code Online (Sandbox Code Playgroud)

相反,越来越命名属性的列表Color,Shape,Children,FirstName,等,我期待,我所得到的恰恰是2和性能,XElement_Print.

我想,我可以遍历XElement我的真实数据中的所有s,并将一组子元素名称组合在一起.然后从我的样本数据中获取子元素名称集,并比较这两组.如果两组相等(例如,它们之间的差异是空集),那么我就知道我已经涵盖了样本数据中的所有基础.

但是,我使用XmlProvider正是因为我希望处理的麻烦XElement和它的怪癖(如XName到处都是,而不是字符串等).我知道可以检索XmlProvider提供的类型的有效属性列表,因为Atom中的自动完成下拉列表(通过Ionide)正好给出了我:所有有效属性的列表.但是,当应用于XmlProvider提供的类型时,标准.Net反射方法似乎没有达到我期望的效果.

如此以来,反射似乎并没有做什么,我期待,有什么我做得到了XmlProvider我的类型创建有效的属性列表?

Tom*_*cek 6

XML类型提供程序是一种擦除类型提供程序,表示XML元素的所有对象都将成为FSharp.Data.Runtime.BaseTypes.XmlElement编译代码中调用的相同类型的值.提供的属性将被删除,并被一段代码替换,该代码通过名称查找访问属性值.

这意味着反射将永远无法看到提供的属性.获得这些的唯一方法是访问底层XElement并直接使用它.例如,要获取子元素,您可以编写:

[ for e in firstObject.XElement.Elements() -> e.Name.LocalName ]
Run Code Online (Sandbox Code Playgroud)

在样本的第一个元素上,返回一个列表["color"; "shape"; "children"].