You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

问题

在将Azure DevOps的REST响应反序列化为多个类的过程中,JSON响应的某一属性包含带有内联Schema信息的XML。该Schema并非固定,因为它包含用户生成的列名和值组成的表格(以XML形式呈现),因此编译前无法确定反序列化目标对象的结构。请问如何将内联Schema转换为自定义反序列化器可使用的运行时生成对象结构?或者这种做法是否正确?

示例XML

<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>

当前自定义反序列化器代码

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;
}
解决方案

1. 使用DataSet动态解析(最优方案)

你提供的XML是标准的ADO.NET DataSet格式,DataSet的ReadXml方法可以自动识别内联Schema并完成数据解析,无需提前定义固定类:

public override object? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
    var xml = reader.GetString();
    var dataSet = new DataSet();
    using var stringReader = new StringReader(xml);
    dataSet.ReadXml(stringReader);
    
    // 解析后可直接通过Tables访问数据,也可转为字典列表方便后续处理
    var targetTable = dataSet.Tables["Table1"];
    var result = new List<Dictionary<string, object>>();
    foreach (DataRow row in targetTable.Rows)
    {
        var rowDict = new Dictionary<string, object>();
        foreach (DataColumn column in targetTable.Columns)
        {
            rowDict[column.ColumnName] = row[column] ?? DBNull.Value;
        }
        result.Add(rowDict);
    }
    return result;
}

这种方案完全适配动态Schema,无需编译时确定结构,是处理此类场景的首选。

2. 使用XDocument手动解析(轻量方案)

如果不想依赖DataSet,可以用LINQ to XML手动遍历节点提取数据:

public override object? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
    var xml = reader.GetString();
    var doc = XDocument.Parse(xml);
    // 跳过Schema节点,直接获取数据行
    var dataRows = doc.Descendants().Where(node => node.Name.LocalName == "Table1");
    var result = new List<Dictionary<string, string>>();
    foreach (var row in dataRows)
    {
        var rowDict = row.Elements()
                        .ToDictionary(element => element.Name.LocalName, element => element.Value);
        result.Add(rowDict);
    }
    return result;
}

该方式更轻量,但需要自行处理数据类型转换,适合结构简单的场景。

3. 运行时生成类型(不推荐)

如果必须生成强类型对象,可以通过System.Reflection.Emit或第三方库根据Schema动态创建类,但这种做法复杂度高、维护成本大,性能也不如前两种方案,仅在有强类型绑定硬性需求时考虑。

原有做法的正确性

你当前用XmlSerializer反序列化到固定NewDataSet类的方式,仅适用于Schema完全固定的场景。一旦用户修改列名或新增列,代码会直接失效,因此原有做法不适用于动态Schema的场景,建议替换为上述动态解析方案。


内容的提问来源于stack exchange,提问作者Pebermynte Lars

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 17:57:48