2012-04-25 147 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()採用默認值,因此它始終有一個值。

要添加新的價值的文件比較簡單,一旦你有等級區分的,因爲你可以簡單的寫另一個屬性的一類,讓如果它不存在,它返回一個默認值。