Linq to XML使用唯一父级创建元素

时间:2016-11-29 18:30:58

标签: c# xml linq linq-to-xml

使用此Linq语句创建XML

new XElement(ns + "SpecialRegisters",
  from reg in registers
  where reg.IsUpdateRegister
  select new XElement(ns + "UpdateRegisters",
    new XElement(ns + "RegID",
        new XAttribute("ID", registers.IndexOf(reg).ToString().PadLeft(2, '0'))
    )
  )
)

是否可以使用多个RegID创建唯一的UpdateRegisters元素。 如果没有更新寄存器,则不应存在任何UpdateRegisters元素。

2 个答案:

答案 0 :(得分:3)

你可以这样做:

var result=new XElement(ns + "SpecialRegisters");
var updateRegister=register.Where(e=>e.IsUpdateRegister);// To not repeat the same query twice
if(updateRegister.Count()>0)
{
 result.Add( new XElement(ns + "UpdateRegisters", 
                          updateRegister.Select((e,i)=> new XElement(ns + "RegID",i));
}

更新

如果你想在同一个声明中完成所有这些,那么你可以这样做:

 var updateRegister=register.Where(e=>e.IsUpdateRegister);// To not repeat the same query twice
 var result=new XElement(ns + "SpecialRegisters", updateRegister.Any()?
                         new XElement(ns + "UpdateRegisters", updateRegister.Select((e,i)=> new XElement(ns + "RegID",i)):null );

我的解决方案基于你的(miguelmpn)

速度并不重要,因为我保存了一个简单的小文件..

new XElement(ns + "SpecialRegisters", Registers.Registers.Singleton.Any(x => x.IsUpdateRegister) ?
                     new XElement(ns + "UpdateRegisters", Registers.Registers.Singleton.Where(e => e.IsUpdateRegister).Select((e, i)=> new XElement(ns + "RegID", i))) : null)

答案 1 :(得分:1)

我认为Enumerable.Aggregate方法重载之一很适合这项任务。

var specialRegisters = 
new XElement(ns + "SpecialRegisters", 
             Registers.Registers.Singleton.Where(reg => reg.IsUpdateRegister)
                                          .Select((reg, i) => new XElement(ns + "RegID", i))
                                          .Aggregate(new XElement(ns + "UpdateRegisters"), 
                                                     (upReg, reg) => 
                                                     {
                                                         upReg.Add(reg);
                                                         return upReg;
                                                     }, 
                                                     upReg => upReg.HasElements ? upReg : null));

这种方法只会枚举一次收集 Aggregate方法的第三个参数是此方法的关键值,如果未添加任何元素,则返回null

我自己的意见发表评论:但我的意图是通过将所有内容放在同一个linq查询来保持代码更清晰。

我认为在一个声明中保持这种逻辑并不是一种干净的方法。我认为清洁的一个想法是,你的代码的读者会更快地理解你的意图。

您可以将创建UpdateRegisters元素提取到专用方法

private XElement CreateUpdateRegistersOrNullIfEmpty(XNamespace ns,
                                                    IEnumerable<YourType> data)
{
    return data.Where(reg => reg.IsUpdateRegister)                
               .Select((reg, i) => new XElement(ns + "RegID", i))
               .Aggregate(new XElement(ns + "UpdateRegisters"), 
                          (upReg, reg) => 
                          {
                              upReg.Add(reg);
                              return upReg;
                          }, 
                          upReg => upReg.HasElements ? upReg : null));
}

然后使用它

var specialRegisters = 
    new XElement(ns + "SpecialRegisters", 
                 CreateUpdateRegistersOrNullIfEmpty(ns, Registers.Registers.Singleton));