解决 将XML反序列化为对象-主要属性名称在XML元素中

jmooney5115

新成员
已加入
2018年10月16日
留言内容
4
编程经验
5-10
你好。我在寻找将以下XML反序列化为易于使用的对象的最佳方法时遇到问题。使用C#到XML转换器,我有一个可用的对象,可以在其中序列化和反序列化对象。问题是使用这种XML我必须使用LINQ来提取属性值。我使用的主要属性名称存储在一个名为Name的XML元素中。反序列化XML将给我一个设置列表。该设置包含2个属性,名称&价值; LINQ是我知道获取值的唯一方法。

我有一个包装器类,它使用反序列化的对象,并具有XML中每个“设置”属性的属性。包装器中属性的getter / setter包含所需的LINQ。必须有更好的方法来做到这一点吗?

仅具有属性Description的包装对象。

C#:
public class ObjectWrapper{    public string Description
    {
        get
        {
            var result = "";

            try
            {
                if (obj is null) return result;

                var columns = obj.Setting.Where(q => q.Name == "Description").ToList();

                if (columns.Count == 1)
                    result = columns.Single().Value.ToString();
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Failed to parse Description obj. Ex: " + ex.ToString());
            }

            return result;
        }
        set
        {
            if (string.IsNullOrEmpty(value)) return;

            try
            {
                if (obj is null) return;

                var columns = obj.Setting.Where(q => q.Name == "Description").ToList();

                if (columns.Count == 1)
                    columns.Single().Value = value;
                else
                {
                    //if Name doesn't exist, create it and assign it.
                    var Name = new Setting
                    {
                        Name = "Description",
                        Value = value
                    };

                    obj.Setting.Add(Name);
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Failed to parse Description obj. Ex: " + ex.ToString());
            }
        }
    }
}


XML格式

C#:
<Object>
  <Processor>
    <Pages>
      <Page>
        <Name>Settings</Name>
        <Row>
          <Setting>
            <Name>Enable</Name>
            <Value>True</Value>
          </Setting>
          <Setting>
            <Name>Name</Name>
            <Value>value</Value>
          </Setting>
          <Setting>
            <Name>Description</Name>
            <Value>value</Value>
          </Setting>
        </Row>
        <Row>
          <Setting>
            <Name>Enable</Name>
            <Value>True</Value>
          </Setting>
          <Setting>
            <Name>Name</Name>
            <Value>value</Value>
          </Setting>
          <Setting>
            <Name>Description</Name>
            <Value>value</Value>
          </Setting>
        </Row>
      </Page>
    </Pages>
  </Processor>
</Object>




将上面的代码插入此站点以生成XML: //xmltocsharp.azurewebsites.net/


C#:
/*     Licensed under the Apache License, Version 2.0
    
[URL]http://www.apache.org/licenses/LICENSE-2.0[/URL]
*/
using System;
using System.Xml.Serialization;
using System.Collections.Generic;
namespace Xml2CSharp
{
    [XmlRoot(ElementName="Setting")]
    public class Setting {
        [XmlElement(ElementName="Name")]
        public string Name { get; set; }
        [XmlElement(ElementName="Value")]
        public string Value { get; set; }
    }

    [XmlRoot(ElementName="Row")]
    public class Row {
        [XmlElement(ElementName="Setting")]
        public List<Setting> Setting { get; set; }
    }

    [XmlRoot(ElementName="Page")]
    public class Page {
        [XmlElement(ElementName="Name")]
        public string Name { get; set; }
        [XmlElement(ElementName="Row")]
        public List<Row> Row { get; set; }
    }

    [XmlRoot(ElementName="Pages")]
    public class Pages {
        [XmlElement(ElementName="Page")]
        public Page Page { get; set; }
    }

    [XmlRoot(ElementName="Processor")]
    public class Processor {
        [XmlElement(ElementName="Pages")]
        public Pages Pages { get; set; }
    }

    [XmlRoot(ElementName="Object")]
    public class Object {
        [XmlElement(ElementName="Processor")]
        public Processor Processor { get; set; }
    }
}
 
Last edited:

约翰·H

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
1,051
地点
挪威
编程经验
10+
您可以在此处粘贴xml Xml2CSharp.com |将您的XML示例转换为与XmlSerializer兼容的C#类 如您所说,将生成的类复制到新的代码文件(空的.cs文件)中。
请注意,它需要准确的xml数据来生成集合属性,例如,如果xml具有多个Page对象,则示例文件也需要该文件,转换器才能看到它。这里的示例具有单个Page对象,该对象将转换为单个item属性。

然后,您可以像以下示例一样反序列化xml: 如何:从XML文件(C#)读取对象数据微软文档 Xml2CSharp.Object类型。

现在,您可以遍历行和设置:
foreach (var row in overview.Processor.Pages.Page.Row)
{
    foreach (var setting in row.Setting)
    {
        //setting.Name 
        //setting.Value
    }
}

我使用反序列化示例中的“概述”变量名称,以方便参考。

还存在一个名为xsd.exe的.Net工具,该工具可以执行类似操作,但可能无法立即使用,并且可能会生成更为复杂的架构/类。这也与VS中的“将Xml作为类粘贴”选项相同。我可以发现,对于您的示例x​​ml,我认为它只是产生了一片混乱。
 

jmooney5115

新成员
已加入
2018年10月16日
留言内容
4
编程经验
5-10
谢谢回复。您在这里给了我一个主意,我可以遍历每行/设置并使用反射来获取属性值。这比获得属性值的数百行LINQ更好。


我正在继承一个项目,我相信他们使用xsd.exe从XML生成C#。没错,它生成了FAR更复杂的类。
 

约翰·H

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
1,051
地点
挪威
编程经验
10+
为什么要使用反射?通常,当您具有带有属性名称的字符串并且想要动态地从对象获取PropertyInfo及其值时,通常使用这种方法,这里您已经有一个具有这些已知属性的对象。
 

jmooney5115

新成员
已加入
2018年10月16日
留言内容
4
编程经验
5-10
为什么要使用反射?通常,当您具有带有属性名称的字符串并且想要动态地从对象获取PropertyInfo及其值时,通常使用这种方法,这里您已经有一个具有这些已知属性的对象。


也许我想念一些东西。该代码不知道如何拆分属性(启用,名称,&说明)作为设置存在于每一行中。每行包含许多设置。该设置包含属性名称和属性值。

我创建了一个示例项目来说明它的外观。 //github.com/jmooney5115/funkyXmlSerialization

Pl4h2PL.png




我想要的是:

  • 目的
    • 处理器
      • 页数
            • 启用字符串
            • 字串名称
            • 字符串说明

我得到的是:
  • 目的
    • 处理器
      • 页数
            • 环境
              • 字符串名称=启用
              • 字符串值=真
            • 环境
              • 字符串名称=名称
              • 字符串值= jmooney
            • 环境
              • 字符串名称=说明
              • 字符串值= csharpforums.net上的用户

 

约翰·H

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
1,051
地点
挪威
编程经验
10+
我知道了。那是xml结构的问题,而不是代码。要得到"what you want"没有工作的xml数据应该是这样的:
HTML:
        <Row>
            <Enable>True</Enable>
            <Name>value</Name>
            <Description>value</Description>
        </Row>
否则,您必须阅读xml文件并手动创建自己定义的类的对象。例如,假设您只需要行并定义了此类:
public class Row
{
    public string Enable { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
}

顺便说一句,“启用”看起来应该是布尔值。

然后,您读取xml并创建对象:
var doc = XDocument.Load(@"d:\sample.xml");
var rows = new List<Row>();
foreach (var row in doc.Descendants("Row"))
{
    var row = new Row();
    foreach (var setting in row.Elements("Setting"))
    {
        var name = setting.Element("Name").Value;
        var value = setting.Element("Value").Value;
        row.GetType().GetProperty(name).SetValue(row, value);
    }
    rows.Add(row);
}

在这里,我仅在一行中使用了反射,但是可以对每个属性使用不同的switch语句,例如设置row.Enable = Convert.ToBoolean(value);
 
最佳 底部