如何找不到元素,如何解析xml文件并返回默认值

bea*_*man 1 c# xml linq-to-xml

我在C#中编写了一个简单的方法来解析给定的xml文件并返回特定节点的值.它工作正常,但如果找不到节点而不是抛出异常,我也想返回默认值.我怎样才能做到这一点?这种方法可以写得更好吗?感谢您提供的任何帮助.约翰

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

<?xml version='1.0' encoding='utf-8'?>
<automationSettings>
    <vmDomain>
        <domainName value = "Domain"/>
        <domainUsername value = "username"/>
        <domainPassword value = "password"/>
    </vmDomain>
</automationSettings>
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 6

让我们从摆脱异常"处理"开始吧.未找到的节点是"合理预期"的错误,我们要确保不会导致异常.应该抛出其他异常 - 例如根本找不到文件,或者不是有效的XML.

接下来,让我们停止使用查询表达式 - 当你只使用一个select子句时,它并没有真正为你买任何东西.

作为下一步,我将停止分配configFilePath可能是一个字段.写这个字段作为副作用对我来说似乎是一个非常糟糕的主意.让我们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();
}
Run Code Online (Sandbox Code Playgroud)

如果它找不到元素或属性,那么现在将抛出异常.我们可以像这样修复:

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

现在,如果Elements()返回一个空序列,则没有任何内容可供选择,FirstOrDefault()并将返回null.如果是一个元素,它不具有的value属性,x.Attribute("value")将返回null,并从显式转换XAttribute到string将返回null.

虽然我们正在使用它,但我们只使用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();
}
Run Code Online (Sandbox Code Playgroud)

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

  • 它允许呼叫者从"未提供设置"中区分"设置已提供但为空"
  • 它允许调用者使用null-coalescing运算符来指定默认值:

    var setting = ReadConfigurationFile("a", "b", "c", "d") ?? "some default value";
    
    Run Code Online (Sandbox Code Playgroud)