c# - XML 到列表转换器? XML 是正确的工具吗?

标签 c# php xml

我是从 PHP 转到 C#,所以请原谅我的一些术语。

目前我正在做一个需要将多个配置文件存储在一个文件中的小项目,所以我决定使用 XML,因为 INI 文件(通常我去找基于文本的人)并不真正支持C#。至少不是令人满意的方式。

这是我的 XML 文件的基本结构:

<profile name="FooBar">
    <btnA pressed="actionA" released="actionB" />
    <btnB pressed="actionX" released="actionY" />
    ...
</profile>
<profile name="XYZ">
    <btnA pressed="actionA" released="actionB" />
    <btnB pressed="actionX" released="actionY" />
    ...
</profile>

在 PHP 中,我会生成一个具有以下结构的关联数组:

<?php
  foo = array(
    'FooBar' => array(
      'btnA_pressed' => 'actionA',
      'btnA_released' => 'actionB'
      // ...
    ),
    'XYZ' => array(
      // ...
    )
  );

编辑开始

应用类结构:

  • 设置(包含所有配置文件和对当前配置文件的引用)
  • 简介(见下文)

配置文件类:

public class Profile 
{
    private string _name;
    public string Name 
    {
        get { return this._name; }
        set { this._name = value;}
    }

    private string _btnA_pressed;
    public string BtnA_Pressed { get; set; }
    // and so on...

    public Profile(var data) { // arg is a placeholder
        // associate the data with the properties
    }
}

简而言之,设置类包含所有配置文件和对所选配置文件的引用。对配置文件的访问通过 Settings.CurrentProfile.propertie_Name()

编辑结束

现在的问题是,如何在 C# 中实现相同或相似的功能?或者是否有更好的方法来实现同样的目标?

提前感谢您的帮助!

最佳答案

使用 LINQ2XML 可以很容易地操作 XML 结构。无需类型化模型(类)。

读取包含许多 profile 节点的 XML 文件(我假设您的 XML 文件是正确的并且有一个根节点),看起来像这样:

// read existing XML structure
var xml = XDocument.Load("d:\\temp\\xml\\profile.xml");
// take all profile elements
var profiles = xml.Root.Elements("profile").ToList();
foreach (var profile in profiles)
{
    Console.WriteLine(profile.Attribute("name").Value);
    // find all button elements
    var buttons = profile
                    .Elements()
                    .Where (e => e.Name.ToString().StartsWith("btn"));
    // list elements
    foreach (var button in buttons)
    {
        // tag name
        var name = button.Name.ToString();
        // attributes
        var pressed = button.Attribute("pressed").Value;
        var released = button.Attribute("released").Value;
        Console.WriteLine(String.Format("{0} - P'{1}' - R'{2}'", name, pressed, released));
    }
}

输出是:

FooBar
btnA - P'actionA' - R'actionB'
btnB - P'actionX' - R'actionY'
XYZ
btnA - P'actionA' - R'actionB'
btnB - P'actionX' - R'actionY'

string 中读取单个配置文件 XML 结构,然后创建一个新的结构如下所示:

var xmlCode = @"<profile name=""FooBar""><btnA pressed=""actionA"" released=""actionB"" /><btnB pressed=""actionX"" released=""actionY"" /></profile>";

try
{
    // read existing XML structure
    var xml = XDocument.Parse(xmlCode); // XDocument.Load("c:\\path\\to\\file.xml");
    // find all button elements
    var buttons = xml.Root
                     .Elements()
                     .Where (e => e.Name.ToString().StartsWith("btn"));
    // list elements
    foreach (var button in buttons)
    {
        // tag name
        var name = button.Name.ToString();
        // attributes
        var pressed = button.Attribute("pressed").Value;
        var released = button.Attribute("released").Value;
        Console.WriteLine(String.Format("{0} - P'{1}' - R'{2}'", name, pressed, released));
    }
    // create xml
    // root element
    var newXml = new XElement("profile", new XAttribute("name", "FooBaz"), 
                    new XElement("btnA", 
                        new XAttribute("pressed", "actionX"), 
                        new XAttribute("released", "actionXR")),
                    new XElement("btnB", 
                        new XAttribute("pressed", "actionZ"), 
                        new XAttribute("released", "actionZR")));
    Console.WriteLine(newXml.ToString());
}
catch (Exception exception)
{
    Console.WriteLine(exception.Message);
}

输出是:

btnA - P'actionA' - R'actionB'
btnB - P'actionX' - R'actionY'
<profile name="FooBaz">
    <btnA pressed="actionX" released="actionXR" />
    <btnB pressed="actionZ" released="actionZR" />
</profile>

您可以使用 LINQ2XML 读取数据并填充您的 Profile 类型的对象列表,如下所示:

// read existing XML structure
var xml = XDocument.Load("d:\\temp\\xml\\profile.xml");
// take all profile elements
var profiles = xml.Root.Elements("profile").ToList();
var listOfProfiles = new List<Profile>();
foreach (var profile in profiles)
{
    var profileObject = new Profile("");
    profileObject.Name = profile.Attribute("name").Value;
    // find all button elements
    var buttons = profile
                    .Elements()
                    .Where (e => e.Name.ToString().StartsWith("btn"));
    // list elements
    foreach (var button in buttons)
    {
        // attributes
        var pressed = button.Attribute("pressed").Value;
        var released = button.Attribute("released").Value;
        profileObject.BtnA_Pressed = pressed;
    }
    listOfProfiles.Add(profileObject);
}

您还可以使用 XML serialization - 您需要将您的 XML 结构描述为一个类(类型化模型)并反序列化(将 XML 文件读入您​​的类)。 序列化(将您的 XML 结构写入文件)。序列化方法的通用实现。反序列化看起来像这样:

public void SerializeModel<T>(string fqfn, T entity)
{
    var xmls = new XmlSerializer(entity.GetType());
    var writer = new StreamWriter(fqfn);
    xmls.Serialize(writer, entity);
    writer.Close();
}

public T DeserializeModel<T>(string fqfn)
{
    var fs = new FileStream(fqfn, FileMode.Open);
    var xmls = new XmlSerializer(typeof(T));
    var r = (T) xmls.Deserialize(fs);
    fs.Close();
    return r;
}

描述您的 Profile 类和其中包含的列表的类型化模型如下所示(注意不同 XML serialization attributes 的用法):

public class Profiles
{
    [XmlElement(ElementName="Profile")]
    public List<Profile> Profile { get; set; }
}

public class Profile
{
    [XmlArray(ElementName="Buttons")]
    public List<Button> Buttons { get; set; }
    [XmlAttribute]
    public String Name;
}

public class Button
{
    [XmlAttribute]
    public String Pressed { get; set; }
    [XmlAttribute]
    public String Released;
}

创建 XML 文件:

    var profiles = new Profiles();
    var profileA = new Profile();
    var profileB = new Profile();
    var buttonA = new Button();
    var buttonB = new Button();

    profileA.Buttons = new List<Button>();
    profileB.Buttons = new List<Button>();
    profiles.Profile = new List<Profile>();

    profileA.Name = "Profile A";
    profileB.Name = "Profile B";
    buttonA.Pressed = "Pressed A";
    buttonA.Released = "Release A";
    buttonB.Pressed = "Pressed B";
    buttonB.Released = "Release B";

    profileA.Buttons.Add(buttonA);
    profileB.Buttons.Add(buttonB);
    profiles.Profile.Add(profileA);
    profiles.Profile.Add(profileB);

    var xmlFile = "d:\\temp\\xml\\profile_model.xml";
    SerializeModel<Profiles>(xmlFile, profiles);

新的 XML 文件看起来像这样(注意,由于 XML serialization in .NET 处理数组/列表的方式,结构略有修改):

<?xml version="1.0" encoding="utf-8"?>
<Profiles xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Profile Name="Profile A">
    <Buttons>
      <Button Released="Release A" Pressed="Pressed A" />
    </Buttons>
  </Profile>
  <Profile Name="Profile B">
    <Buttons>
      <Button Released="Release B" Pressed="Pressed B" />
    </Buttons>
  </Profile>
</Profiles>

然后可以像这样读取文件:

    var input = DeserializeModel<Profiles>(xmlFile);
    foreach (var profile in input.Profile)
    {
        var b = profile.Buttons.First();
        Console.WriteLine(String.Format("{0} - {1} - {2}", profile.Name, b.Pressed, b.Released));
    }

输出符合预期:

Profile A - Pressed A - Release A
Profile B - Pressed B - Release B

这两种方法各有优缺点。

IMO 对您问题的回答(稍作改动)XML 是将结构化数据保存到文件的正确方法吗? 是 - 绝对是!如今,XML 是表示/操作/交换结构化数据和一般数据(数据保存在字符串中)的标准之一。正如有人已经提到的那样,INI 文件并不是真正用来表示复杂的嵌套结构。

关于c# - XML 到列表转换器? XML 是正确的工具吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23300686/

相关文章:

c# - 你如何 Response.Redirect 到另一个同名但端口不同的网站?

c# - 是否可以在不创建对象实例的情况下获取对象属性名称字符串?

c# - 使用 Youtube .net API 上传视频并将其设置为不公开

php - PHP和mysqli- fatal error :在非对象上调用成员函数bind_param()

php - 从字符串中提取美元金额 - PHP 中的正则表达式

XML Row TYPE(xml数据输入)

c# - 我可以从 asp.net 5 中的单例实例中解析范围内的实例吗

android - strings.xml 中的 "Message description not found"警告

java - XML 资源中的变量 - 将值从父级传递给子级

php - 如何从一行中选择多个名称?