1

我正在开发 ac# 控制台应用程序,它有一个包含程序设置的 xml 配置文件。

我想在 xml 文件中添加注释,以显示可以使用<!--My Comment-->. 出于某种原因,当我把它放进去时,就好像 C# 认为这是文件的结尾并且没有读取文件的其他部分,没有抛出错误并且程序没有停止响应它继续运行其余部分的代码。

下面是配置文件。

<?xml version="1.0" encoding="utf-8" ?>
<options>
  <database>
    <item key="server" value="localhost" />
    <item key="database" value="emailserver" />
    <item key="username" value="myusername" />
    <item key="password" value="mypassword" />
    <item key="port" value="3306" />
  </database>
  <EmailServer>
    <item key="logFile" value="email_server.txt" />
    <!--You can use fileCopy or database-->
    <item key="logManageMode" value="fileCopy" />
    <item key="ip_address" value="127.0.0.1" />
    <item key="smtpPort" value="26" />
    <item key="requireAuthentication" value="false" />
  </EmailServer>
</options>

如果我不将该评论放入其中,它将读入整个文件。下面是读取 XML 文件的代码。

public Dictionary<string, string> readConfig(string sectionName, bool soapService=false, Dictionary<string, string> config=null)
        {
            Dictionary<string, string> newConfig = null;
            if (config == null)
            {
                newConfig = new Dictionary<string, string>();
            }
            //Dictionary<string, string> config = new Dictionary<string, string>();
            try
            {
                XmlDocument configXml = new XmlDocument();
                string configPath = "";
                if (soapService)
                {
                    string applicationPath = HttpContext.Current.Server.MapPath(null);
                    configPath = Path.Combine(applicationPath, "config.xml");
                    configXml.Load(configPath);
                }
                else
                {
                    configXml.Load("config.xml");
                }

                XmlNodeList options = configXml.SelectNodes(string.Format("/options/{0}", sectionName));
                XmlNodeList parameters = configXml.GetElementsByTagName("item");
                foreach (XmlNode option in options)
                {
                    foreach (XmlNode setting in option)
                    {
                        string key = setting.Attributes["key"].Value;
                        string value = setting.Attributes["value"].Value;

                        if (config == null)
                        {
                            newConfig.Add(key, value);
                        }
                        else
                        {
                            config.Add(key, value);
                        }
                    }
                }
            }
            catch (KeyNotFoundException ex)
            {
                Console.WriteLine("Config KeyNotFoundException: {0}", ex.Message);
            }
            catch (XmlException ex)
            {
                Console.WriteLine("Config XmlException: {0}", ex.Message);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Config Exception: {0}", ex.Message);
                Console.WriteLine("StackTrace: {0}", ex.StackTrace);
            }
            if (config == null)
            {
                return newConfig;
            }
            return config;
        }

感谢您的任何帮助,您可以提供。

4

2 回答 2

4

您的评论是一个节点。所以当你遍历节点时:

 foreach (XmlNode option in options) 
                 { 
                     foreach (XmlNode setting in option) 
                     { 
                         string key = setting.Attributes["key"].Value; 
                         string value = setting.Attributes["value"].Value;

您在 commebnt 处触发了 try/catch 块,因为该节点不包含“键”或“值”属性。

您可以使用该NodeType属性来确定节点是否为评论。例如:

 foreach (XmlNode option in options) 
                 { 
                     foreach (XmlNode setting in option) 
                     { 
                         if (setting.NodeType == XmlNodeType.Comment)
                         {
                             continue;
                         }
                         string key = setting.Attributes["key"].Value; 
                         string value = setting.Attributes["value"].Value;

如果节点不是元素,另一种选择是继续:

if (setting.NodeType != XmlNodeType.Element)

根据 Tomalak:实际上这与 OP 的原始代码一样脆弱。在 XML 中插入与注释不同的节点类型,它将再次爆炸。只需在循环中选择一个特定的 XmlNodeList: XmlNodeList settings = option.SelectNodes("item[@key and @value]");

于 2012-08-15T17:27:04.220 回答
1

这是您的代码的一个版本,它不会阻塞未知的 XML 节点类型,而且更短一些。

关键是您不能简单地遍历子节点列表并期望节点是特定的。

如果您想在特定节点上工作,请始终选择特定的东西 - 在这种情况下,名称item包含一个@key和一个属性的元素节点。@value

XmlNodeList settings = option.SelectNodes("./item[@key and @value]");

这是完整的代码:

public Dictionary<string, string> readConfig(string sectionName, bool soapService=false, Dictionary<string, string> config=null)
{
    Dictionary<string, string> myConfig = config ?? new Dictionary<string, string>();
    try
    {
        XmlDocument configXml = new XmlDocument();
        string configPath = "config.xml";
        if (soapService)
        {
            string applicationPath = HttpContext.Current.Server.MapPath(null);
            configPath = Path.Combine(applicationPath, "config.xml");
        }
        configXml.Load(configPath);

        XmlNodeList options = configXml.SelectNodes(string.Format("/options/{0}", sectionName));
        foreach (XmlNode option in options)
        {
            XmlNodeList settings = option.SelectNodes("./item[@key and @value]");
            foreach (XmlNode setting in settings)
            {
                myConfig.Add(setting.Attributes["key"].Value, setting.Attributes["value"].Value);
            }
        }
    }
    catch (KeyNotFoundException ex)
    {
        Console.WriteLine("Config KeyNotFoundException: {0}", ex.Message);
    }
    catch (XmlException ex)
    {
        Console.WriteLine("Config XmlException: {0}", ex.Message);
    }
    catch (Exception ex)
    {
        Console.WriteLine("Config Exception: {0}", ex.Message);
        Console.WriteLine("StackTrace: {0}", ex.StackTrace);
    }
    return myConfig;
}
于 2012-08-15T17:47:54.967 回答