C# 从C读取XML配置数据文件#
我有一个名为config.XML的独立XML文件,它与我的应用程序一起使用,基本上包含两个部分: 1) 全局设置 2) 服务器列表,包括设置 基本上,全局设置将包含我的程序将用于每个服务器列表的数据库用户名和数据库密码 服务器列表条目包含服务器列表、一些文件名、数据库用户名和数据库密码。这里唯一重要的一点是,如果我在服务器列表中指定用户名/密码,那么它将使用该用户名/密码,而不是全局数据库用户名和密码。或者,换言之,如果数据库用户名和密码未在servewr列表条目中定义,则它将使用全局数据库用户名pasword 我的程序基本上循环遍历xml配置文件,对每个DB2服务器执行一些数据库查询,处理信息并创建报告。它今天起作用了,但我确实有一些问题 1) 每次向XML配置文件中添加新元素时,都必须为创建的每个节点添加新元素,否则会出现XML解析错误 2) 我希望对配置XML文件进行分类,而不是将所有内容都放在同一个节点中,并包含空元素 示例XML如下所示:C# 从C读取XML配置数据文件#,c#,xml,C#,Xml,我有一个名为config.XML的独立XML文件,它与我的应用程序一起使用,基本上包含两个部分: 1) 全局设置 2) 服务器列表,包括设置 基本上,全局设置将包含我的程序将用于每个服务器列表的数据库用户名和数据库密码 服务器列表条目包含服务器列表、一些文件名、数据库用户名和数据库密码。这里唯一重要的一点是,如果我在服务器列表中指定用户名/密码,那么它将使用该用户名/密码,而不是全局数据库用户名和密码。或者,换言之,如果数据库用户名和密码未在servewr列表条目中定义,则它将使用全局数据库用户
<?xml version="1.0" encoding="utf-8" ?>
<Config>
<Global>
<OutputFolder>C:\DATA\Configs\DB2\</OutputFolder>
<DBUser>DB2ADMIN</DBUser>
<DBPassword>%SecretPassword%</DBPassword>
<FTPFiles>false</FTPFiles>
<FTPTcpIp>127.0.0.1</FTPTcpIp>
<FTPUser>FTPLogin1</FTPUser>
<FTPPassword>P@ssw0rd</FTPPassword>
<FTPRemoteFolder>/configs</FTPRemoteFolder>
</Global>
<Servers>
<Server enabled="true">
<Category>Report1</Category>
<TcpIp>192.168.26.107</TcpIp>
<Database>SampleData</Database>
<User></User>
<Password></Password>
<Report1FileNameList>List1.txt</Report1FileNameList>
<Report1FileNameRoutes>Routes1.txt</Report1FileNameRoutes>
<Report1FileNameRouteTimeouts>Timeouts1.txt</Report1FileNameRouteTimeouts>
<Report1FileNameEndpoints></Report1FileNameEndpoints>
<Report2FilenameServers></Report2FilenameServers>
<Report2FilenameRoutingGroup></Report2FilenameRoutingGroup>
</Server>
<Server enabled="true">
<Category>Report1</Category>
<TcpIp>192.168.26.107</TcpIp>
<Database>SampleDataB</Database>
<User></User>
<Password></Password>
<Report1FileNameList>List1.txt</Report1FileNameList>
<Report1FileNameRoutes>Routes1.txt</Report1FileNameRoutes>
<Report1FileNameRouteTimeouts>Timeouts1.txt</Report1FileNameRouteTimeouts>
<Report1FileNameEndpoints></Report1FileNameEndpoints>
<Report2FilenameServers></Report2FilenameServers>
<Report2FilenameRoutingGroup></Report2FilenameRoutingGroup>
</Server>
<Server enabled="true">
<Category>Report2</Category>
<TcpIp>192.168.26.107</TcpIp>
<Database>SampleDataE</Database>
<User></User>
<Password></Password>
<Report1FileNameList></Report1FileNameList>
<Report1FileNameRoutes></Report1FileNameRoutes>
<Report1FileNameRouteTimeouts></Report1FileNameRouteTimeouts>
<Report1FileNameEndpoints>Endpoints2.txt</Report1FileNameEndpoints>
<Report2FilenameServers>Servers2.txt</Report2FilenameServers>
<Report2FilenameRoutingGroup>Groups2.txt</Report2FilenameRoutingGroup>
</Server>
<Server enabled="true">
<Category>Report2</Category>
<TcpIp>192.168.26.108</TcpIp>
<Database>SampleDatabase1_D</Database>
<User></User>
<Password></Password>
<Report1FileNameList></Report1FileNameList>
<Report1FileNameRoutes></Report1FileNameRoutes>
<Report1FileNameRouteTimeouts></Report1FileNameRouteTimeouts>
<Report1FileNameEndpoints>Endpoints2.txt</Report1FileNameEndpoints>
<Report2FilenameServers>Servers2.txt</Report2FilenameServers>
<Report2FilenameRoutingGroup>Groups1.txt</Report2FilenameRoutingGroup>
</Server>
</Servers>
// load XML file
try
{
// Config/Global
System.Xml.XPath.XPathDocument doc = new System.Xml.XPath.XPathDocument(@"config.xml");
foreach (System.Xml.XPath.XPathNavigator child in doc.CreateNavigator().Select("Config/Global"))
{
xml_global_outputFolder = child.SelectSingleNode("OutputFolder").Value;
xml_global_DBuser = child.SelectSingleNode("DBUser").Value;
xml_global_DBpassword = child.SelectSingleNode("DBPassword").Value;
xml_global_FTPFiles = bool.Parse(child.SelectSingleNode("FTPFiles").Value);
xml_global_FTPTcpIp = child.SelectSingleNode("FTPTcpIp").Value;
xml_global_FTPUser = child.SelectSingleNode("FTPUser").Value;
xml_global_FTPPassword = child.SelectSingleNode("FTPPassword").Value;
xml_global_FTPRemoteFolder = child.SelectSingleNode("FTPRemoteFolder").Value;
}
// Config/Servers
//System.Xml.XPath.XPathDocument doc = new System.Xml.XPath.XPathDocument(@"config.xml");
foreach (System.Xml.XPath.XPathNavigator child in doc.CreateNavigator().Select("Config/Servers/*"))
{
//string xml_enabled = child.GetAttribute("Enabled", "");
string xml_category = child.SelectSingleNode("Category").Value;
string xml_tcpip = child.SelectSingleNode("TcpIp").Value;
string xml_database = child.SelectSingleNode("Database").Value;
string xml_user = child.SelectSingleNode("User").Value;
string xml_password = child.SelectSingleNode("Password").Value;
Console.WriteLine("Connecting to {0} using database {1} for {2} information...", xml_tcpip, xml_database, xml_category);
// if node user value is empty, use global
if (xml_user == string.Empty)
{
DB2_user = xml_global_DBuser;
}
else
{
DB2_user = xml_user;
}
// if node password value is empty, use global
if (xml_password == string.Empty)
{
DB2_password = xml_global_DBpassword;
}
else
{
DB2_password = xml_password;
}
string txtFilename = string.Empty;
string csvFilename = string.Empty;
switch (xml_category.ToUpper())
{
case "SAMPLE":
txtFilename = Path.Combine(xml_global_outputFolder, @"EMPLOYEE.csv");
csvFilename = Path.Combine(xml_global_outputFolder, Path.GetFileNameWithoutExtension(@"EMPLOYEE.csv"));
ExecuteQuery(xml_category, "SAMPLE", xml_tcpip, DB2_user, DB2_password, xml_database, csvFilename, txtFilename, option_debug);
break;
}
Console.WriteLine("");
}
}
catch (Exception e)
{
Console.WriteLine("Exception: {0}", e.Message);
Environment.Exit(1);
}
Environment.Exit(0);
}
我想理想情况下,我希望创建特定于节点的配置,如果元素为空,代码应该能够处理缺少的元素或空元素。可能使用类别的属性来代替?比如:
<Config>
<Global>
<OutputFolder></OutputFolder>
<DBUser></DBUser>
<DBPassword><DBPassword>
</Global>
<Servers category="Report1">
<Server>
<TcpIP>whatever</TcpIP>
<User>whatever></User>
<Password>whatever></Password>
</Server>
<Server>
<TcpIP>whatever</TcpIP>
<User>whatever></User>
<Password>whatever></Password>
</Server>
<Server>
<TcpIP>whatever</TcpIP>
<User>whatever></User>
<Password>whatever></Password>
</Server>
</Server>
<Servers category="Report2">
<Server>
<TcpIP>whatever</TcpIP>
<User>whatever></User>
<Password>whatever></Password>
</Server>
<Server>
<TcpIP>whatever</TcpIP>
<User>whatever></User>
<Password>whatever></Password>
</Server>
<Server>
<TcpIP>whatever</TcpIP>
<User>whatever></User>
<Password>whatever></Password>
</Server>
</Server>
<Servers category="AccessList">
<Server>
<TcpIP>whatever</TcpIP>
<Database>whatever></Database>
<Active>whatever</Active>
</Server>
<Server>
<TcpIP>whatever</TcpIP>
<Database>whatever></Database>
<Active>whatever</Active>
</Server>
<Server>
<TcpIP>whatever</TcpIP>
<Database>whatever></Database>
<Active>whatever</Active>
</Server>
</Server>
</Config>
无论什么
不管怎样>
不管怎样>
无论什么
不管怎样>
不管怎样>
无论什么
不管怎样>
不管怎样>
无论什么
不管怎样>
不管怎样>
无论什么
不管怎样>
不管怎样>
无论什么
不管怎样>
不管怎样>
无论什么
不管怎样>
无论什么
无论什么
不管怎样>
无论什么
无论什么
不管怎样>
无论什么
您需要做的是创建一组类,每个类代表每组节点。如果您想使用,它们将帮助您处理空节点和默认值:
在全局文件夹中读取和写入OutputFolder:
DirectoryInfo outputFolder = ConfigFile.Read.Global.OutputFolder;
ConfigFile.Write(file => file.Global.OutputFolder = outputFolder);
课程包括:
public class ConfigFile : IDisposable
{
internal XElement self;
string file = "path to a file";
public ConfigFile()
{
if(File.Exists(file))
self = XElement.Load(file);
else
self = new XElement("Config");
}
public void Dispose() { self.Save(file); }
public static ConfigFile Read { get { return new ConfigFile(); } }
public static void Write(Action<ConfigFile> action)
{
using(ConfigFile file = new ConfigFile())
action(file);
}
public Global Global
{ get { return _Global ?? (_Global = new Global(self.GetElement("Global"))); } }
Global _Global;
public Servers Servers
{ get { return _Servers ?? (_Servers = new Servers(self.GetElement("Servers"))); } }
Servers _Servers
public class Global
{
internal XElement self;
public Global(XElement self) { this.self = self; }
public DirectoryInfo OutputFolder
{
get { return self.Get<DirectoryInfo>("OutputFolder", null); }
set { self.Set("OutputFolder", value, false); }
}
}
public class Servers
{
internal XElement self;
public Servers(XElement self) { this.self = self; }
public void Add(Server server)
{
self.Add(server.self);
}
public string Category
{
get { return self.Get("category", string.Empty); }
set { self.Set("category", value, true); }
}
public Server[] Items
{ get { return self.GetEnumerable("Server", x => new Server(x)).ToArray(); } }
public class Server
{
internal XElement self;
public Server() { self = new XElement("Server"); }
public Server(XElement self) { this.self = self; }
public bool Active
{
get { return self.Get("Active", false); }
set { self.Set("Active", value, true); }
}
}
}
}
公共类配置文件:IDisposable
{
内在自我;
string file=“文件路径”;
公共配置文件()
{
如果(File.Exists(File))
self=XElement.Load(文件);
其他的
self=新元素(“配置”);
}
public void Dispose(){self.Save(文件);}
公共静态配置文件读取{get{return new ConfigFile();}}
公共静态无效写入(操作)
{
使用(ConfigFile file=new ConfigFile())
行动(文件);
}
公共全球
{get{return{u Global???({u Global=new Global(self.GetElement(“Global”);}
全球(Global);;
公共服务器
{获取{返回{u服务器???({u服务器=新服务器(self.GetElement(“服务器”));}
服务器
公共类全球
{
内在自我;
公共全局(XElement self){this.self=self;}
公共目录信息输出文件夹
{
get{return self.get(“OutputFolder”,null);}
set{self.set(“OutputFolder”,value,false);}
}
}
公共类服务器
{
内在自我;
公共服务器(XElement self){this.self=self;}
公共void添加(服务器)
{
self.Add(server.self);
}
公共字符串类别
{
get{return self.get(“category”,string.Empty);}
set{self.set(“category”,value,true);}
}
公用服务器[]项
{get{return self.GetEnumerable(“Server”,x=>newserver(x)).ToArray();}
公共类服务器
{
内在自我;
公共服务器(){self=new-XElement(“服务器”);}
公共服务器(XElement self){this.self=self;}
公共图书馆
{
get{return self.get(“Active”,false);}
set{self.set(“Active”,value,true);}
}
}
}
}
GetElement()
优于Element()
,因为它处理元素节点不存在的情况Get()
采用默认值,因此它总是有一个值
一旦有了类的区别,向文件中添加一个新值就更简单了,因为您可以简单地将另一个属性写入一个类,如果它不存在,就让它返回一个默认值