我是从 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/