从 C# 读取 XML 配置数据文件 [英] Reading an XML Configuration Data File from C#

查看:27
本文介绍了从 C# 读取 XML 配置数据文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个名为 config.xml 的独立 XML 文件,它与我的应用程序一起包含基本上包含两个部分:

I have a standalone XML file named config.xml that goes with my application that contains basically two sections:

1) 全局设置2) 服务器列表,包括设置

1) Global settings 2) Server List, including settings

基本上,全局设置将包含我的程序将用于每个服务器列表的数据库用户名和数据库密码.

Basically, the global settings would contain a Database Username and Database Password that my program would use for each server listing.

服务器列表条目包含服务器列表、一些文件名、数据库用户名和数据库密码.这里唯一重要的是,如果我在服务器列表中指定用户名/密码,那么它将使用它而不是全局数据库用户名和密码.或者,换种说法,如果在 serverwr 列表条目中没有定义数据库用户名和密码,它将使用全局数据库用户名密码.

The Server listing entries contain a list of servers, along with some filenames, and Databse Username and Database Password. The only thing significant here is that if I specify a Username/password in the server list, then it will use this rather than the global database username and password. Or, said differently, if the database username and password is not defined within the servewr list entry, it will use the global database username pasword.

我的程序基本上遍历 xml 配置文件,并对每个 DB2 服务器执行一些数据库查询,处理信息并创建报告.它今天有效,但我确实有一些问题......

My program basically loops through and xml configuration file and executes some database queries against each DB2 server and processes the information and creates a report. It works today, but I do have a few issues...

1) 每次我向 XML 配置文件添加新元素时,我都必须为我创建的每个节点添加它,否则我会收到 XML 解析错误.

1) Every time I add a new element to my XML configuration file, I have to add it for each node that I have created, otherwise I get XML parse errors.

2) 我想对我的配置 XML 文件进行分类,而不是将所有内容都集中在同一个节点中并包含空元素.

2) I'd like to categeory my configuration XML file rather than lump everything in one the same node and include empty elements.

示例 XML 如下:

<?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);
    }

我想理想情况下,我想创建特定于节点的配置,如果元素为空,代码应该能够处理丢失的元素或空元素.也许使用类别的属性,而不是?类似的东西:

I guess ideally, I'd like to create node-specific configurations and if the element is blank, the code should be able to handle either a missing element or an empty element. Maybe using an attribute for the category, instead? Something like:

   <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>

推荐答案

您需要做的是创建一组类,每个类代表每组节点.如果您想使用这些扩展程序,他们将帮助您空节点和默认值:

What you need to do is create a set of classes with each class representing each group of nodes. If you'd like to use these extensions, they will help you with empty nodes and default values:

在全局中读写输出文件夹:

Read and Write the OutputFolder in Global:

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); }
            }
        }
    }
}

GetElement() 优于 Element() 因为它处理元素节点不存在的情况.Get() 采用默认值,因此它总是有一个值.

GetElement() is superior to Element() because it handles cases where the element node doesn't exist. Get() takes a default value, therefore it always has a value.

一旦有了类区分,向文件中添加新值就更简单了,因为您可以简单地将另一个属性写入一个类,如果该类不存在,则让它返回一个默认值.

To add a new value to the file is simpler once you have class distinction, because you can simply write another property to a class and let it return a default value if it doesn't exist.

这篇关于从 C# 读取 XML 配置数据文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆