如何在包含特定元素值的XElement之间删除特定XElement

本文关键字:XElement 之间 删除 元素 包含特 | 更新日期: 2023-09-27 18:22:28

Xdocument Xd(从xml文件映射):

<pfsense>
  <nat>
    <outbound>
      <mode>advanced</mode>
    </outbound>
    <rule>
      <source>
        <any />
      </source>
      <destination>
        <network>wanip</network>
        <port>63350</port>
      </destination>
      <protocol>tcp</protocol>
      <target>10.100.100.15</target>
      <local-port>11</local-port>
      <interface>wan</interface>
      <descr><![CDATA[delete this]]></descr>
      <associated-rule-id />
    </rule>
    <rule>
      <source>
        <any />
      </source>
      <destination>
        <network>wanip</network>
        <port>63350</port>
      </destination>
      <protocol>tcp</protocol>
      <target>10.100.100.11</target>
      <local-port>11</local-port>
      <interface>wan</interface>
      <descr><![CDATA[don't delete this]]></descr>
      <associated-rule-id />
    </rule>
  </nat>
</pfsense>

我只想删除具有以下描述的规则元素:

<descr><![CDATA[delete this]]></descr>

预期结果是相同的XDocument(Xd),但不包含将删除的条件的XElement。我试过这个:

XElement ruleToDelete = null;
foreach (var x in Xd.Root.Element("nat").Elements("rule"))
{
    if (x.Element("descr")!= null && x.Element("descr").Value == ruleDescription)
    {
        ruleToDelete = x;
        break;
    }
}
if (ruleToDelete != null)
{
    ruleToDelete.Remove();
    //But Xd is the same as before...
}

但是,我希望Xd受到影响。。。

如何在包含特定元素值的XElement之间删除特定XElement

是一个简单的天真解决方案

var elements = Xd.XPathSelectElements("/pfsense/nat//rule[descr/text() = 'delete this']");
elements.Remove();

这样的东西应该可以工作:

xd.Element("pfsense").Elements("nat").Elements("rule").Elements("descr").Where(x => x.Value == "delete this").Remove();

通过使用WhereAny,如:

Xd.Root.Element("nat").Elements("rule").Where
            (x => x.Elements("descr").Any(t => t.Value == ruleDescription)).Remove();

并验证结果:

        Assert.IsFalse(Xd.Root.Element("nat").Elements
            ("rule").Any(x => x.Elements("descr").Any(t => t.Value == ruleDescription)));

这应该对您有效;

正如你可能知道的,元素有一个级别。如果你想做这样的事情,最好使用后代。需要注意的另一点是"Equal"运算符的使用。您可以使用contains,但使用"delete"answers"donnotdelete"这样的值风险太大。另外请注意,即使您有CDATA,它们也不会出现在"Value"中。

class Program
{
    static void Main(string[] args)
    {
        var xdoc = XDocument.Load(@"C:'Xd.xml");
        Console.WriteLine("--------------------");
        Console.WriteLine("BEFORE");
        Console.WriteLine("--------------------");
        Console.WriteLine(xdoc.ToString());
        xdoc.Descendants().Where(d => d.Name.LocalName.Equals("descr") && d.Value.Equals("delete this")).Remove();
        Console.WriteLine("");
        Console.WriteLine("");
        Console.WriteLine("--------------------");
        Console.WriteLine("AFTER");
        Console.WriteLine("--------------------");
        Console.WriteLine(xdoc.ToString());
        Console.ReadLine();
    }
}

刚刚注意到您想要删除"rule"元素。因此,您可以像这样更改查询。

   xdoc.Descendants().Where(d => d.Name.LocalName.Equals("rule") 
            && d.Descendants().Any(dd => dd.Name.LocalName.Equals("descr") && dd.Value.Equals("delete this"))).Remove();