简体   繁体   English

如何在 c# 中使用具有相同名称但不同属性和结构的元素反序列化 XML

[英]How to deserialize XML with elements with same name, but different attributes and structure in c#

I have an XML response with the following structure:我有一个 XML 响应,其结构如下:

 <Response>
    <Block id="1">
       <Some_Data_1><Some_Data_1>
       <Some_Data_2><Some_Data_2>
    </Block>
    <Block id="2">
        <Another_Data_3><Another_Data_3>
        <Another_Data_4><Another_Data_4>
        <Another_Data_5><Another_Data_5>
    </Block>
    <Block id="3">
        ...
    </Block>
</Response>

I need to deserialize each Block to the separate object in the fastest way.我需要以最快的方式将每个块反序列化为单独的 object。 So far I came up with manual searching for each block using LINQ, and deserializing each block separately, like that:到目前为止,我想出了使用 LINQ 手动搜索每个块,并分别反序列化每个块,如下所示:

var Xblock1 = root.Elements("Block").FirstOrDefault(e => e.Attribute("id")?.Value == "1");
Block1 block1 = (Block1)(serializer.Deserialize(Xblock1.CreateReader()));

But I believe there is more optimized way to do it.但我相信有更优化的方法来做到这一点。

Appreciate for your time珍惜你的时间

Xml serialization is slow and requires a class and property name. Xml 序列化速度很慢,需要 class 和属性名称。 Instead I recommend Xml Linq which is much faster and doesn't need predefined property names相反,我推荐 Xml Linq 更快并且不需要预定义的属性名称

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XDocument doc = XDocument.Load(FILENAME);

            Dictionary<int, Dictionary<string, string>> dict = doc.Descendants("Block")
                .GroupBy(x => (int)x.Attribute("id"), y => y.Elements()
                    .GroupBy(a => a.Name.LocalName, b => (string)b)
                    .ToDictionary(a => a.Key, b => b.FirstOrDefault()))
                .ToDictionary(x => x.Key, y => y.FirstOrDefault());

        }
    }
}

First method is with Serialize, second is a copy from the answer from @jdweng.第一种方法是使用序列化,第二种是来自@jdweng 的答案的副本。

As said before, the method using Serialize is much slower!如前所述,使用Serialize的方法要慢得多!

For first method you also need a class generated by XSD.EXE which i linked at the end of this answer.对于第一种方法,您还需要一个由 XSD.EXE 生成的 class ,我在这个答案的末尾链接了它。

static void Main(string[] args)
{
    DateTime start;

    start = DateTime.Now;
    XmlSerializer ser2 = new XmlSerializer(typeof(Response));
    FileStream f = new FileStream(FILENAME, FileMode.Open);
    Response response = ser2.Deserialize(f) as Response;

    foreach (var item in response.Block)
    {
        Console.WriteLine(item.id);
    }
    f.Close();

    Console.WriteLine("Method 1: {0}", ((DateTime.Now - start).TotalMilliseconds / 1000));

    start = DateTime.Now;
    XDocument doc = XDocument.Load(FILENAME);

    Dictionary<int, Dictionary<string, string>> dict = doc.Descendants("Block")
        .GroupBy(x => (int)x.Attribute("id"), y => y.Elements()
            .GroupBy(a => a.Name.LocalName, b => (string)b)
            .ToDictionary(a => a.Key, b => b.FirstOrDefault()))
        .ToDictionary(x => x.Key, y => y.FirstOrDefault());

    foreach (var item in dict.Keys)
    {
        Console.WriteLine(item);
    }
    Console.WriteLine("Method 2: {0}", ((DateTime.Now - start).TotalMilliseconds / 1000));

    Console.ReadLine();

}

output: output:

1
2
3
Method 1: 0,0759927
1
2
3
Method 2: 0,0030262

Below codde is generated by XSD.EXE /c file.xsd , so from your XML you should create an XSD (which Visual Studio can do for you): Below codde is generated by XSD.EXE /c file.xsd , so from your XML you should create an XSD (which Visual Studio can do for you):

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

using System.Xml.Serialization;

// 
// This source code was auto-generated by xsd, Version=4.8.3928.0.
// 


/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.8.3928.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=false)]
public partial class Response {
    
    private ResponseBlock[] blockField;
    
    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("Block")]
    public ResponseBlock[] Block {
        get {
            return this.blockField;
        }
        set {
            this.blockField = value;
        }
    }
}

/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.8.3928.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)]
public partial class ResponseBlock {
    
    private string another_Data_3Field;
    
    private string another_Data_4Field;
    
    private string another_Data_5Field;
    
    private string some_Data_1Field;
    
    private string some_Data_2Field;
    
    private string[] textField;
    
    private byte idField;
    
    /// <remarks/>
    public string Another_Data_3 {
        get {
            return this.another_Data_3Field;
        }
        set {
            this.another_Data_3Field = value;
        }
    }
    
    /// <remarks/>
    public string Another_Data_4 {
        get {
            return this.another_Data_4Field;
        }
        set {
            this.another_Data_4Field = value;
        }
    }
    
    /// <remarks/>
    public string Another_Data_5 {
        get {
            return this.another_Data_5Field;
        }
        set {
            this.another_Data_5Field = value;
        }
    }
    
    /// <remarks/>
    public string Some_Data_1 {
        get {
            return this.some_Data_1Field;
        }
        set {
            this.some_Data_1Field = value;
        }
    }
    
    /// <remarks/>
    public string Some_Data_2 {
        get {
            return this.some_Data_2Field;
        }
        set {
            this.some_Data_2Field = value;
        }
    }
    
    /// <remarks/>
    [System.Xml.Serialization.XmlTextAttribute()]
    public string[] Text {
        get {
            return this.textField;
        }
        set {
            this.textField = value;
        }
    }
    
    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public byte id {
        get {
            return this.idField;
        }
        set {
            this.idField = value;
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 将具有相同名称的不同xml元素反序列化为不同的C#类 - Deserialize different xml elements with same name into different C# classes 反序列化JSON不同的结构,但在C#中使用相同的名称 - Deserialize JSON different structure, but the same name in C# 通过C#中的XmlSerializer类反序列化具有相同名称的多个但“不同”的XML元素 - Deserialize multiple but “different” XML elements with the same name through XmlSerializer class in C# C#将具有属性的XML元素反序列化为List - C# Deserialize XML elements with attributes into List 在C#中反序列化具有相同名称的多个XML元素 - Deserialize multiple XML elements with the same name in C# C#获取具有相同名称的所有元素的列表 - XML反序列化 - C# get a list of all elements with the same name - XML Deserialize 在 C# 中反序列化具有不同类型名称的 XML 元素 - Deserialize XML elements with different type name in C# 使用相同元素名称和不同属性名称的 XML 反序列化 - XML Deserialize with same element name and different attributes​ name 在C#中使用属性反序列化XML - Deserialize XML with Attributes in C# 如何将具有不同名称但具有相同属性集的xml元素反序列化为类型化数组/集合 - How to deserialize xml elements that have different names, but the same set of attributes to a typed array/collection
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM