.ReplaceWith()不替换XElement

时间:2013-08-09 15:29:36

标签: c# linq linq-to-xml

在xml文档中,我有以下内容

  ...  
    <TablixMembers>
       <TablixMember>
          <Group Name="Details" />
       </TablixMember>
     </TablixMembers>
   </TablixMember>
     <TablixHeader Name="MyField3" />
     <TablixHeader Name="MyField2" /> 
 </TablixMembers>
</TablixMember>

我有一个for循环,用字段名称查找每个元素(“MyField3,MyField2,...)

for (int g = 0; g < remainingtotals; g++)
{
   groupTotals.Reverse();
   ff.Add(new XElement(ns + "TablixHeader"));
   ff.Descendants(ns + "TablixHeader").Last().SetAttributeValue("Name", groupTotals[g]);

   string nName = GenerateUniqueName("Nsted");
   while (ff.Descendants(ns + "TablixHeader").Any(n => (string)n.Attribute("Name") == groupTotals[g]))
   {
     var newnode = ff.Descendants(ns + "TablixHeader").Where(n => (string)n.Attribute("Name") == groupTotals[g]).Single();
     newnode.ReplaceWith(new XElement(tGroupHeader));
   }

groupTotals.Reverse();
} 

在这个循环中,我有一个List<string> groupTotals,它包含字段的名称。 它可能不需要在while循环中(我添加了这个用于测试)我有一个查找特定字段的查询

var newnode = ff.Descendants(ns + "TablixHeader").Where(n => (string)n.Attribute("Name") == groupTotals[g]).Single();
         newnode.ReplaceWith(new XElement(tGroupHeader));

这将newnode设置为:

<TablixHeader Name="MyField3" xmlns="http://schemas.microsoft.com/sqlserver/reporting/2010/01/reportdefinition" />

在下一行中,我尝试用新的xml元素结构替换此节点

newnode.ReplaceWith(new XElement(tGroupHeader));

tGroupHeader是一个内存流,它包含一个应插入的大型xml元素模板,并替换所选属性名称的当前tablix节点。

当此代码运行时,节点不会被替换。实际上没有任何反应,我在节点上设置了断点,没有抛出xml异常,它只是直接通过它。我假设我要么错误地调用方法,要么选择单个节点是导致它不替换元素的原因。

我还认为这可能是由于注入了一个大的xml结构,但我还使用了一个元素来测试它,例如:

newnode.ReplaceWith(new XElement(ns + "Size"));// ns is the xml namespace for the schema I am using

这也不会导致元素被替换。

任何人都可以对我可能做错的事情提供一些见解吗?

-cheers

1 个答案:

答案 0 :(得分:0)

我终于找到了解决方法,这可能不是最好的方法,但它是可靠的。从我试图查询节点时我可以看到元素将被定位但它不会更新我认为这部分是由于我尝试在一个方法内基于.Descendants()查询进行注入和更新(这可能不对,但这是我所能确定的。)

我使用的解决方法不是在创建元素时尝试导航元素的xml结构,而是添加了具有特定名称的ID属性。

ff.Add(new XElement(ns + "TablixMember"));
ff.Descendants(ns + "TablixMember").Last().SetAttributeValue("Name", groupTotals[g]);
ff.Descendants(ns + "TablixMember").Last().SetAttributeValue("ID", groupedItemTotals[g].GroupPosition.ToString());

然后插入一个XElement,例如

   <TablixMembers>
      <TablixMember>
        <TablixHeader xmlns="http://schemas.microsoft.com/sqlserver/reporting/2010/01/reportdefinition">
         <Size>1in</Size>
            <CellContents>
              <Textbox Name="GroupTotalPPPccc2973356bf4beaa92cb0409b37b8ef" ID="1">
                   <CanGrow>true</CanGrow>
                       <KeepTogether>true</KeepTogether>
<--end snip -->

一旦我添加了id,它就会更简单地查询节点

  var newnode = ff.Descendants(ns + "TablixMember").Where(n => (string)n.Attribute("ID") == groupedItemTotals[g].GroupPosition.ToString()).Single();

然后,我可以使用Replace()更新节点内的元素。 ReplaceWith()SetAttribut()等

在此片段中,我选择了节点,删除了所有子元素,然后注入了新结构

newnode.RemoveAll();
newnode.Add(new XElement(tGroupHeader),
new XElement(ns + "KeepWithGroup"));
newnode.Descendants(ns + "TablixHeader").Last().Descendants(ns + "Textbox").Last().SetAttributeValue("Name", nName);

最后,由于我使用的当前架构不支持ID属性,因此我执行了一些清理以删除任何不受支持的属性。

report.Descendants(ns + "TablixMember").Where(p => (string)p.Attribute("ID") != null).Attributes("ID").Remove();
report.Descendants(ns + "Textbox").Where(p => (string)p.Attribute("ID") != null).Attributes("ID").Remove();

我有兴趣看到其他建议或想法。

感谢