我有一个用户提供的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"))
)));
问题是蜘蛛侠行。由于null,上面的查询无效。
问题
如何处理Linq-to-Xml中的空蜘蛛侠行?
如果用户忘记添加Alias行,我需要能够处理该行为。在这种情况下,别名应该是(a)根本不在Xml中或(b)具有空值
答案 0 :(得分:2)
您可以为此编写一个辅助函数,它将返回XAttribute
或null
。 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)
)));
答案 1 :(得分:1)
另一种方法是在第一个答案中使用这里的三元运算符: example with ternary operator
答案 2 :(得分: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蜘蛛侠并不像蝙蝠侠或超人那么好。
实际上你可以创建以下扩展,它将根据表名和列名从任何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>
答案 3 :(得分: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>