如果未找到元素,如何解析 xml 文件和 return 默认值

How to parse an xml file and return default value if no element found

我用 C# 编写了一个简单的方法来解析给定的 xml 文件和 return 特定节点的值。它工作正常,但如果找不到节点而不是抛出异常,我还想 return 默认值。我怎样才能做到这一点?方法能不能写的更好? 感谢您提供的任何帮助。 约翰

public static string ReadConfigurationFile(string configurationFileName, string root, string section, string name)
{
    try
    {
        String currentDirectory = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
        configFilePath = Directory.GetParent(currentDirectory) + configurationFolder + configurationFileName;

        XDocument configXML = XDocument.Load(configFilePath);
        var result = from setting in
                         configXML.Descendants(root)
                            .Descendants(section)
                     select setting.Element(name).Attribute("value").Value;
        return result.First();
    }
    catch (Exception ex)
    {
        return string.Empty;
    }
}

这是我解析的 XML 文件的示例:

<?xml version='1.0' encoding='utf-8'?>
<automationSettings>
    <vmDomain>
        <domainName value = "Domain"/>
        <domainUsername value = "username"/>
        <domainPassword value = "password"/>
    </vmDomain>
</automationSettings>

让我们从消除异常开始 "handling"。找不到节点是一个 "reasonable to expect" 错误,我们要确保该错误不会导致异常。其他异常 - 例如根本找不到文件或无效 XML - 可能应该被抛出。

接下来,让我们停止使用查询表达式 - 当您只使用 select 子句时,它不会真正给您带来任何好处。

作为下一步,我将停止分配给 configFilePath,这大概是一个字段。作为 side-effect 写入该字段对我来说似乎是一个非常糟糕的主意。让我们也使用 Path.Combine 来组合路径的位...

所以现在我们有:

// Work in progress!
public static string ReadConfigurationFile(
    string configurationFileName,
    string root,
    string section,
    string name)
{
    string currentDirectory = Path.GetDirectoryName(
        Assembly.GetExecutingAssembly().Location);
    var fullConfigPath = Path.Combine(
        Directory.GetParent(currentDirectory),
        configurationFolder,
        configurationFileName);

    var configXml = XDocument.Load(fullConfigPath);
    return configXml.Descendants(root)
                    .Descendants(section)
                    .Select(x => x.Element(name).Attribute("value").Value
                    .First();
}

如果找不到元素或属性,现在将抛出异常。我们可以这样解决:

return configXml.Descendants(root)
                .Descendants(section)
                .Elements(name)
                .Select(x => (string) x.Attribute("value"))
                .FirstOrDefault();

现在,如果 Elements() return 是一个空序列,select 将没有任何内容,而 FirstOrDefault() 将 return 为空。如果 元素并且它没有 value 属性,则 x.Attribute("value") 将 return 为 null,并且从 [=21 显式转换=] 到 string 将 return 为空。

虽然我们这样做,但我们只使用 configXml 进行一次调用,所以让我们内联它,留下:

public static string ReadConfigurationFile(
    string configurationFileName,
    string root,
    string section,
    string name)
{
    string currentDirectory = Path.GetDirectoryName(
        Assembly.GetExecutingAssembly().Location);
    var fullConfigPath = Path.Combine(
        Directory.GetParent(currentDirectory),
        configurationFolder,
        configurationFileName);

    return XDocument.Load(fullConfigPath)
                    .Descendants(root)
                    .Descendants(section)
                    .Elements(name)
                    .Select(x => (string) x.Attribute("value"))
                    .FirstOrDefault();
}

现在,returns null 而不是原始代码所做的空字符串。我认为这样更好,因为:

  • 它允许调用者区分 "the setting was provided but empty" 和 "the setting wasn't provided"
  • 它允许调用者使用null-coalescing运算符来指定一个默认值:

    var setting = ReadConfigurationFile("a", "b", "c", "d") ?? "some default value";