0

我有一个用户提供的 DataTable,其中包含以下信息:

| 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"))
)));

问题是蜘蛛侠行。由于为空,上面的查询不起作用。

问题

  1. 如何处理 Linq-to-Xml 中的空蜘蛛侠行?

  2. 如果用户忘记添加别名行,我需要能够处理该位置。在这种情况下,别名应该是 (a) 根本不在 Xml 中或 (b) 具有空值

4

3 回答 3

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)
)));

如果缺少 Alias 列,这也应该有效,因为如果缺少列,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)
)));
于 2013-03-13T16:15:33.390 回答
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)
        )));

顺便说一句,蜘蛛侠不如蝙蝠侠或超人好


实际上,您可以创建以下扩展,它将根据表名和列名从任何 DataTable 构建 xml(它需要 System.Data.Entity.Design 程序集中的 PluralizationService):

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>
于 2013-03-13T17:30:00.057 回答
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>
于 2013-03-13T17:06:40.567 回答