【问题标题】:How to Parse Optional or Null XML Elements & Attributes with LINQ?如何使用 LINQ 解析可选或空 XML 元素和属性?
【发布时间】:2011-12-09 05:45:12
【问题描述】:

我有以下类型的 XML:

我希望通过这个 XML 填充以下 objectList。

List<Function> objFunctionsList = new List<Function>();

其中Function类如下,

public class Function
{
    public String Name { get ; set; }
    public Parameter ReturnType { get; set; }
    public List<Parameter> Parameters { get; set; }
    public String Library { get; set; }
    public String Signature { get; set; }
    public String Description { get; set; }
    public String Code { get; set; }
}

而Parameter类如下,

public class Parameter
{
    [DefaultValue("")] 
    public String Name { get; set; }

    [DefaultValue("")]
    public String DataType { get; set; }

    [DefaultValue("")]
    public String OccurenceType { get; set; }
}

您可以看到,在 XML 中,一些函数标签具有参数标签,而另一些则没有。我试过这个:

public const string XPATH_NAME = "/Functions/Function/Name";
public const string XPATH_LIBRARY = "/Functions/Function/Library";
public const string XPATH_SIGNATURE = "/Functions/Function/Signature";
public const string XPATH_DESCRIPTION = "/Functions/Function/Description";
public const string XPATH_CODE = "/Functions/Function/Code";

List<Function> objFunctionsList = new List<Function>();

try
{
    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.Load(pXMLPath);

    XmlNodeList nlName = xmlDoc.SelectNodes(Constants.XPATH_NAME);
    XmlNodeList nlLibrary = xmlDoc.SelectNodes(Constants.XPATH_LIBRARY);
    XmlNodeList nlSignature = xmlDoc.SelectNodes(Constants.XPATH_SIGNATURE);
    XmlNodeList nlDescription = xmlDoc.SelectNodes(Constants.XPATH_DESCRIPTION);
    XmlNodeList nlCode = xmlDoc.SelectNodes(Constants.XPATH_CODE);

    // Name, Signature, Library, element should be present in 'Function' node
    if (nlName.Count == nlLibrary.Count
        && nlName.Count == nlSignature.Count
        && nlName.Count == nlDescription.Count
        && nlName.Count == nlCode.Count)
    {
        for (int iCount = 0; iCount < nlName.Count; iCount++)
        {
            Function objFunction = new Function();
            objFunction.Name = nlName[iCount].InnerText.Trim();
            objFunction.Library = nlLibrary[iCount].InnerText.Trim();
            string signature = nlSignature[iCount].InnerText;

            Parameter objReturnType = new Parameter();
            string returnType = (nlSignature[iCount].Attributes[Constants.ATRR_TYPE] == null
                ? Constants.XSNOPARAM
                : nlSignature[iCount].Attributes[Constants.ATRR_TYPE].Value);

            if (returnType.EndsWith(Constants.ASTERIK))
            {
                objReturnType.DataType = returnType.Substring(0, returnType.Length - 1);
                objReturnType.OccurenceType = Constants.OCCURENCES_ASTERISK;
            }
            else if (returnType.EndsWith(Constants.PLUS))
            {
                objReturnType.DataType = returnType.Substring(0, returnType.Length - 1);
                objReturnType.OccurenceType = Constants.OCCURENCES_PLUS;
            }
            else if (returnType.EndsWith(Constants.QUESTION_MARK))
            {
                objReturnType.DataType = returnType.Substring(0, returnType.Length - 1);
                objReturnType.OccurenceType = Constants.OCCURENCES_QUESTION;
            }
            else if (returnType.Length > 0)
            {
                objReturnType.DataType = returnType;
            }

            objFunction.ReturnType = objReturnType;

            objFunction.Parameters = new List<Parameter>();

            objFunction.Signature = signature;
            objFunction.Description = nlDescription[iCount].InnerText.Trim();
            objFunction.Code = nlCode[iCount].InnerText.Trim();

            objFunctionsList.Add(objFunction);
        }
    }
}

但这是基于 XPath 的代码,并且在我之前在函数标签中没有参数标签时使用。

【问题讨论】:

  • 我已经更新了我尝试过的代码
  • 如果一个函数没有参数,那是否意味着它的Parameters成员应该是null,或者是一个空列表,还是没有关系?

标签: c# .net xml linq xml-parsing


【解决方案1】:

正如his answer 中的the article that @NitinRastogi mentions 指出的那样,您可以使用LINQ 的一些方便属性来轻松解决null 或可选值:

  1. 返回集合的方法,例如Elements(),将返回一个空 集合(不是null)如果没有找到结果或者它们被传递为空集合 输入:

    如果将空集合传递给Attributes 扩展方法,它也会返回 一个空集合。

  2. 一些返回单个值的 LINQ 方法,例如 First(),也有 如果没有找到对象,将返回默认值的变体,例如null, 而不是引发异常。对于First(),它的变体是 FirstOrDefault()

因此,在您的情况下,由于 Parameters 对于您的 Function 对象是可选的,您可以选择使用等于 nullParameters 或空列表来初始化它们。

案例1:用null初始化

如果你想将它们初始化为null,你可以这样做:

var doc = // XDocument.Load() or XDocument.Parse() ...
var functions =
    from f in doc.Root.Elements()
    select new
    {
        // ...
        Parameters = f.Elements("parameters").Elements().Count() == 0
            ? null
            : (
                from p in f.Elements("parameters").Elements()
                select new {
                    DataType = p.Attribute("type"),
                    Name = p.Attribute("name"),
                    Occurence = p.Attribute("occurence")
              })
              .ToList()
        // ...
    };

案例2:用列表初始化(0个或更多元素)

但这会导致很多丑陋的null 检查代码。一种更简单的方法是仅使用包含 0 个或更多元素的列表进行初始化。如果没有参数,这些 LINQ 和 XElement 集合方法都将返回一个空集合,因此函数上的 Parameters 属性将只是一个空列表而不是 null:

var doc = // XDocument.Load() or XDocument.Parse() ...
var functions =
    from f in doc.Root.Elements()
    select new
    {
        // ...
        Parameters = (
            from p in f.Elements("parameters").Elements()
            select new {
                DataType = p.Attribute("type"),
                Name = p.Attribute("name"),
                Occurence = p.Attribute("occurence")
            })
            .ToList()
        // ...
    };

【讨论】:

    猜你喜欢
    • 2010-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多