2

基本的に次の 2 つのセクションを含むアプリケーションに対応する config.xml という名前のスタンドアロン XML ファイルがあります。

1) グローバル設定 2) 設定を含むサーバーリスト

基本的に、グローバル設定には、プログラムが各サーバー リストに使用するデータベース ユーザー名とデータベース パスワードが含まれます。

サーバー リスト エントリには、サーバーのリスト、いくつかのファイル名、およびデータベース ユーザー名とデータベース パスワードが含まれています。ここで重要なのは、サーバー リストでユーザー名/パスワードを指定すると、グローバル データベースのユーザー名とパスワードではなく、これが使用されることです。または、別の言い方をすれば、データベースのユーザー名とパスワードが serverwr リスト エントリ内で定義されていない場合、グローバル データベースのユーザー名のパスワードが使用されます。

私のプログラムは基本的にxml構成ファイルをループし、各DB2サーバーに対していくつかのデータベースクエリを実行し、情報を処理してレポートを作成します。今日はうまくいきましたが、いくつか問題があります...

1) XML 構成ファイルに新しい要素を追加するたびに、作成したノードごとに要素を追加する必要があります。そうしないと、XML 解析エラーが発生します。

2) すべてを 1 つのノードにまとめて空の要素を含めるのではなく、構成 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>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>
4

1 に答える 1

3

必要なことは、各クラスがノードの各グループを表す一連のクラスを作成することです。これらの拡張機能を使用したい場合は、空のノードとデフォルト値を使用するのに役立ちます:

グローバルで 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()はデフォルト値を取るため、常に値があります。

クラスの区別があれば、ファイルに新しい値を追加するのは簡単です。クラスに別のプロパティを書き込むだけで、存在しない場合はデフォルト値を返すことができるからです。

于 2012-04-26T00:04:37.163 に答える