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

时间:2016-01-07 17:01:19

标签: 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;
    }
}

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

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

1 个答案:

答案 0 :(得分: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();
}

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

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

现在,如果Elements()返回一个空序列,则无法选择,FirstOrDefault()将返回null。如果 是一个元素且它没有value属性,x.Attribute("value")将返回null,并且显式转换为XAttribute到{{1}将返回null。

虽然我们正在使用它,但我们只使用string进行一次通话,所以让我们通过以下方式进行内联:

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(); } 而不是原始代码所做的空字符串。我认为这更好,因为:

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

    null