在运行时使用内联 XSD 将 XML 反序列化为 POCO

Deserializing XML into POCO at runtime using inline XSD

提问人:Pebermynte Lars 提问时间:11/9/2023 更新时间:11/21/2023 访问量:40

问:

作为来自 Azure DevOps 的 REST 响应的一部分,该响应正在反序列化为多个类, JSON 响应的属性之一包含具有内联架构信息的 XML。

架构不是固定的,因为它包含用户生成的列名和值表,表述为 XML。 所以在编译之前,我不知道如何描述我要反序列化的对象。

如何将内联架构转换为运行时生成的对象结构,我的自定义反序列化程序可以使用? 或者这甚至是正确的方法吗?

xml 可能看起来像这样,其中是我的根元素并且始终已知。其余部分取决于用户生成的表。<NewDataSet>

<NewDataSet>
<xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">    
    <xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:Locale="">      
        <xs:complexType>        
            <xs:choice minOccurs="0" maxOccurs="unbounded">          
                <xs:element name="Table1">            
                    <xs:complexType>              
                        <xs:sequence>                
                            <xs:element name="status" type="xs:string" minOccurs="0" />                
                            <xs:element name="petId" type="xs:string" minOccurs="0" />                
                            <xs:element name="petName" type="xs:string" minOccurs="0" />                
                            <xs:element name="petStatus" type="xs:string" minOccurs="0" />              
                        </xs:sequence>            
                    </xs:complexType>          
                </xs:element>        
            </xs:choice>      
        </xs:complexType>    
    </xs:element>  
</xs:schema>  
<Table1>    
    <status>available</status>    
    <petId>0</petId>    
    <petName>doggie</petName>    
    <petStatus>available</petStatus>  
</Table1>  
<Table1>    
    <status>pending</status>    
    <petId>1</petId>    
    <petName>cat</petName>    
    <petStatus>pending</petStatus>  
</Table1>  
<Table1>    
    <status>sold</status>    
    <petId>2</petId>    
    <petName>fish</petName>    
    <petStatus>sold</petStatus>  
</Table1>
</NewDataSet>

我的反序列化程序会从根元素的 json 响应中提取 xml,如下所示,就像它对其他已知数据结构所做的那样:

public override NewDataSet? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            // Read XML string and parse it to object of type Steps
            var xml = reader.GetString();
            var serializer = new XmlSerializer(typeof(NewDataSet));

            Log.Debug($"Microsoft.VSTS.TCM.LocalDataSource XML: {xml}");

            using var stringReader = new StringReader(xml);
            return serializer.Deserialize(stringReader) as NewDataSet;

        }
C# XML 反序列化

评论

1赞 Alexander Petrov 11/10/2023
尝试使用 DataSetDataTable
0赞 Pebermynte Lars 11/20/2023
使用内联 XSD 反序列化为 DataSet,这正是我所需要的。如果你把它写成一个答案,反序列化程序返回一个 DataSet,我会接受它。

答:

1赞 Alexander Petrov 11/21/2023 #1

DataSet 能够使用内联 XML 架构加载所示格式的 XML。

DataSet dataSet = new DataSet();
dataSet.ReadXml("test.xml");

label.Text = dataSet.Tables[0].TableName;

dataGridView.DataSource = dataSet.Tables[0];

使用数据绑定,它们可以立即显示在网格中。

将架构中的类型更改为,您将无法在网格单元格中输入非数值。petIdxs:int

<xs:element name="petId" type="xs:int" minOccurs="0" />

这可作为使用从 Xml 架构加载的数据类型的证明。DataTable

1赞 Pebermynte Lars 11/21/2023 #2

基于 @alexander-petrov 的答案,我最终采用了这种反序列化方法来处理 XML:

    public override DataSet Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        // Read XML string and convert it into a DataSet
        var xml = reader.GetString();
        using var stringReader = new StringReader(xml);

        DataSet dataSet = new DataSet();
        dataSet.ReadXml(stringReader, XmlReadMode.ReadSchema);

        return dataSet;
    }

它将读取内联 XSD,使用我可以迭代的表构建一个数据集,而无需知道 XML 输入的初始大小和形状。