2012-04-25 114 views
2

一个XML配置数据文件我有一个名为config.xml独立的XML文件,与我的应用程序进入,基本上包含两个部分:阅读从C#

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

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

服务器列表条目包含的服务器列表,一些文件名一起,或与数据库用户名和数据库密码。唯一重要的是,如果我在服务器列表中指定用户名/密码,那么它将使用此名称而不是全局数据库用户名和密码。或者,换句话说,如果数据库用户名和密码没有在servewr列表条目中定义,它将使用全局数据库用户名pasword。

我的程序基本上循环遍历和XML配置文件,并执行对每个DB2服务器的一些数据库查询和处理信息并创建一个报告。今天的工作,但我有几个问题...

1)我每次添加新元素到我的XML配置文件,我要补充的是,我已经创建的每个节点,否则我得到的XML解析错误。

2)我想我categeory配置XML文件,而不是一次性的一切相同的节点,包括空元素。

示例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>[email protected]</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> 

回答

3

您需要做的是创建一组类,每个类代表每组节点。如果您想使用these extensions,他们会帮你空节点和默认值:

读取和写入全球的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); } 
      } 
     } 
    } 
} 

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

要添加新的价值的文件比较简单,一旦你有等级区分的,因为你可以简单的写另一个属性的一类,让如果它不存在,它返回一个默认值。