2013-03-13 44 views
0

我有以下信息的用户提供的数据表:处理空值和缺失列的LINQ到XML

| Name  | Alias  | 
|--------------------------- 
| Batman | Dark Knight | 
| Superman | Man of Steel | 
| Spiderman | null   | 

我需要这个表转换成XML发送到存储过程并获得Xml类似于以下内容:

<Superheroes> 
    <Superhero Name="Batman" Alias="Dark Knight"/> 
    <Superhero Name="Superman" Alias="Man of Steel"/> 
    <Superhero Name="Spiderman"/> 
</Superheroes> 

我想使用Linq-to-Xml(用于学习目的)来解决此问题。这是我到目前为止:

XDocument doc; 

doc = new XDocument(
     new XElement("Superheroes", 
     from row in table.AsEnumerable() 
      select new XElement("Superhero", 
       new XAttribute("Name", row.Field<string>("Name")), 
       new XAttribute("Alias", row.Field<string>("Alias")) 
))); 

问题是蜘蛛侠行。上面的查询由于null而不起作用。

问题

  1. 如何处理在LINQ到XML中的空行蜘蛛侠?

  2. 如果用户忘记添加别名行,我需要能够处理该位置。在这种情况下,别名应该不包括(一)未在全部或(b)提取XML具有空值

回答

2

你可以写这样的辅助函数要么返回XAttributenull。 Linq to XML将忽略null

private XAttribute GetAlias(DataRow row) 
{ 
    if(row.Field<string>("Alias") != null) 
    { 
     return new XAttribute("Alias", row.Field<string>("Alias")); 
    } 
    return null; 
} 

并且像这样使用它。

doc = new XDocument(
    new XElement("Superheroes", 
    from row in table.AsEnumerable() 
     select new XElement("Superhero", 
      new XAttribute("Name", row.Field<string>("Name")), 
      GetAlias(row) 
))); 

这也应该工作,如果别名列缺,因为Field<T>(string)扩展方法应该返回null如果列丢失。

或者,如果您只想在列缺失或值为null时使用空字符串属性,则可以执行以下操作。

doc = new XDocument(
    new XElement("Superheroes", 
    from row in table.AsEnumerable() 
     select new XElement("Superhero", 
      new XAttribute("Name", row.Field<string>("Name")), 
      new XAttribute("Alias", row.Field<string>("Alias") ?? string.Empty) 
))); 
+0

您的缺少的属性解决方案的伟大工程。不幸的是,如果列丢失,字段(字符串)会引发错误。 – 2013-03-13 18:46:59

+0

在这种情况下,您只需要在助手函数中添加一个检查是否存在该列。 – juharr 2013-03-13 19:09:06

0

您可以在线if声明(使用?: operator)扩展您的查询,并检查是否Alias在当前行中设置:

doc = new XDocument(
     new XElement("Superheroes", 
     from row in table.AsEnumerable() 
     select new XElement("Superhero", 
      new XAttribute("Name", row.Field<string>("Name")), 
      (row.Field<string>("Alias") != null ? new XAttribute("Alias", row.Field<string>("Alias")) : null)) 
)); 

返回null不会改变生成的XML可言,所以doc包含正是你希望它包含:

<Superheroes> 
    <Superhero Name="Batman" Alias="Dark Knight" /> 
    <Superhero Name="Superman" Alias="Man of Steel" /> 
    <Superhero Name="Spiderman" /> 
</Superheroes> 
1

如果属性名称应与列标题相同,那么再解决一个问题。你可以只添加这些属性,其中有没有空值:

doc = new XDocument(
     new XElement("Superheroes", 
      from row in table.AsEnumerable() 
      select new XElement("Superhero", 
       from column in table.Columns.Cast<DataColumn>() 
       let value = row.Field<string>(column) 
       where value != null // just filter out nulls 
       select new XAttribute(column.Caption, value) 
     ))); 

BTW蜘蛛侠并不像蝙蝠侠或超人


其实你可以创建这样的扩展,它会从任何建立XML数据表基于表名和列名(它需要PluralizationService从System.Data.Entity.Design组装):

public static class Extensions 
{ 
    public static XDocument ToXml(this DataTable table) 
    { 
     if (String.IsNullOrEmpty(table.TableName)) 
      throw new ArgumentException("Table name is required"); 

     var pluralizationService = PluralizationService 
       .CreateService(new CultureInfo("en-US")); 
     string elementName = pluralizationService.Singularize(table.TableName); 

     return new XDocument(
      new XElement(table.TableName, 
       from row in table.AsEnumerable() 
       select new XElement(elementName, 
        from column in table.Columns.Cast<DataColumn>() 
        let value = row.Field<string>(column) 
        where value != null 
        select new XAttribute(column.Caption, value) 
        ) 
       ) 
      ); 
    } 
} 

用法很简单:

DataTable table = new DataTable("Superheroes"); // name is required 
table.Columns.Add("Name"); 
table.Columns.Add("Alias"); 
table.Rows.Add("Batman", "Dark Knight"); 
table.Rows.Add("Superman", "Man Of Steel"); 
table.Rows.Add("Spiderman", null); 
var doc = table.ToXml(); 

而且结果是相当不错

<Superheroes> 
    <Superhero Name="Batman" Alias="Dark Knight" /> 
    <Superhero Name="Superman" Alias="Man Of Steel" /> 
    <Superhero Name="Spiderman" /> 
</Superheroes> 
+0

你能解释一下PluralizationService的情况吗?为什么你不能使用表名? – 2013-03-13 19:18:25

+0

@J当然。 PluralizationService提供了构造复数和单数形式的单词的方法。 EF使用它来从多个表名中构造实体名称。这就是为什么我在这个解决方案中使用它 - 表格有复数名称“超级英雄”。 PluralizationService以单数形式为行创建元素名称,即'超级英雄' – 2013-03-13 20:06:46

+1

天才。谢谢! – 2013-03-13 21:12:29