【问题标题】:Remove child XML node from parent with where clause使用 where 子句从父节点中删除子 XML 节点
【发布时间】:2014-01-03 17:45:22
【问题描述】:

对于 LINQ 和 XML 来说真的很陌生。我希望有人能告诉我在尝试从 XElement 中删除子节点时我做错了什么。

这是我的 XML 示例: (我正在尝试删除与用户选择的关系相对应的“关系”)

<Bill>
  <Element>
    <Name>AccountNumber</Name>
    <Regex></Regex>
    <Left></Left>
    <Right></Right>
    <Top></Top>
    <Bottom></Bottom>
    <Index>0</Index>
    <Relations></Relations>
  </Element>
  <Element>
    <Name>BillDate</Name>
    <Regex></Regex>
    <Left></Left>
    <Right></Right>
    <Top></Top>
    <Bottom></Bottom>
    <Index>1</Index>
    <Relations>
      <Relation>AccountNumber.RightOf.Right.0</Relation>
      <Relation>AccountNumber.Below.Top.-10</Relation>
      <Relation>AccountNumber.Above.Bottom.-10</Relation>
    </Relations>
  </Element>

如果我的 WPF GUI,当用户单击删除关系时,我只想从父级中删除该关系。

这是我尝试过的众多方法之一:

private void DeleteButton_Click(object sender, RoutedEventArgs e)
{
    List<RelationsDetailView> details = (List<RelationsDetailView>)DetailsView.ItemsSource;

    XElement parentElement = (from Node in ocrVar.Xml.Descendants("Element")
                              where Node.Element("Index").Value == ocrVar.SelectedItem.Index.ToString()
                              select Node).FirstOrDefault();
    XElement child = parentElement.Element("Relations").Elements("Relation").Where(xel => xel.Element("Relation").Value == (details[DetailsView.SelectedIndex].Relation)).FirstOrDefault();
    child.Remove();
    ocrVar.Xml.Save(ocrVar.xmlPath);
}

【问题讨论】:

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


    【解决方案1】:

    您的Where 谓词不正确。 xel 已经是 &lt;relation&gt; 元素,因此您不必再次调用Element("Relation")

    您还应该将XElement.Value 替换为(string)XElement 以防止NullReferenceException

    .Where(xel => (string)xel == (details[DetailsView.SelectedIndex].Relation))
    

    或者您可以将FirstOrDefault 与谓词一起使用而不是Where().FirstOrDefault() 链:

    XElement child = parentElement.Element("Relations").Elements("Relation").FirstOrDefault(xel => (string)xel == details[DetailsView.SelectedIndex].Relation);
    

    【讨论】:

    • 完美,感谢您的解释。此外,关于防止 NullReferenceException 的一些建议也很棒。
    • 不客气。您也可以将XElement 转换为int 并将您的第一个查询条件更改为where (int)Node.Element("Index")== ocrVar.SelectedItem.Index
    • 好电话。我假设将某些内容转换为 int 并比较 int 比将其他内容转换为字符串并比较两个字符串更好?只是好奇。
    • 快速问题.. 当调用 child.Remove() 或 child.RemoveNodes() 时,它的行为并不像我想象的那样。与其删除整个节点(AccountNumber.Below.Top.-10),不如将其替换为看似空的节点()。这是为什么?有没有办法把它全部删除?谢谢
    • 想通了。将第二个查询保存到“child”,然后调用 child.Remove() 将标记的一部分留在那里。简单地说“parentElement.Element("Relations").Elements("Relation").FirstOrDefault(xel => (string)xel == details[DetailsView.SelectedIndex].Relation).Remove();”修好了。
    【解决方案2】:
    xel.Element("Relation").Value == (details[DetailsView.SelectedIndex].Relation
    

    这个条件总是返回 false,也许你想要这样的东西?

    (string)xel.Element("Relation") == (details[DetailsView.SelectedIndex].Relation.ToString())
    

    【讨论】:

    • 快速问题.. 当调用 child.Remove() 或 child.RemoveNodes() 时,它的行为并不像我想象的那样。与其删除整个节点(AccountNumber.Below.Top.-10),不如将其替换为看似空的节点()。这是为什么?有没有办法把它全部删除?谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-09
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 2013-02-04
    • 2021-06-11
    相关资源
    最近更新 更多