0

Xdocument Xd (mapped from xml file):

<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>

I want to remove only the rule element that has the following description:

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

Expected result is the same XDocument (Xd) without the XElement of the condition that will be deleted. I tried this one:

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...
}

But, I want the Xd to be affected...

dckuehn
  • 2,427
  • 3
  • 27
  • 37
Giannis Grivas
  • 3,374
  • 1
  • 18
  • 38
  • What is Xd? Is it your xml file? – Kosala W Nov 18 '15 at 00:23
  • Xd is the Xdocument variable – Giannis Grivas Nov 18 '15 at 00:24
  • Consider a big xml file mapped to thisXd Xdocument that may have many rules and finally this file will be saved. – Giannis Grivas Nov 18 '15 at 00:27
  • This may sound silly. But I have seen people forget to save the document after doing this kind of changes. Have you saved the doc and looked whether it's actually removed or not? – Kosala W Nov 18 '15 at 02:06
  • @KosalaW it's not that case.The problem with my first approach is that the change takes effect only in the new created xelement variable and not in the actual Xd doc.Check again the answers and the code. – Giannis Grivas Nov 18 '15 at 02:28
  • As you may aware Element has a level. If you want to do something like this, you are better off with using descendants. Have a look at my answer. – Kosala W Nov 18 '15 at 03:46

4 Answers4

0

Something like this should work:

xd.Element("pfsense").Elements("nat").Elements("rule").Elements("descr").Where(x => x.Value == "delete this").Remove();
Harsh
  • 1,309
  • 8
  • 14
  • It seems nice but what about if there is no rule element or an element without inside ? – Giannis Grivas Nov 18 '15 at 00:37
  • In addition you take only one Element and you check inside this if the descr is the description.There are many rules.what about that? – Giannis Grivas Nov 18 '15 at 00:45
  • Multiplicity of rules can be easily accomodated by changing Element("Rule") to Elements("Rule"). Check my edited code. Secondly, if there is no rule element or element without "descr", it will essentially be ignored. – Harsh Nov 18 '15 at 00:52
0

A simple naive solution will be

var elements = Xd.XPathSelectElements("/pfsense/nat//rule[descr/text() = 'delete this']");
elements.Remove();
Orel Eraki
  • 11,940
  • 3
  • 28
  • 36
0

By using Where and Any like:

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

And to validate the result:

        Assert.IsFalse(Xd.Root.Element("nat").Elements
            ("rule").Any(x => x.Elements("descr").Any(t => t.Value == ruleDescription)));
Giannis Grivas
  • 3,374
  • 1
  • 18
  • 38
0

This should work for you;

As you may be aware Element has a level. If you want to do something like this, you are better off with using descendants. Other point to note is the use of "Equal" operator. You can use contains, but it's too risky with values like "delete" and "do not delete". Also note, even though you have CDATA they are not present in the "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();
    }
}

Just noticed you wanted to remove "rule" element. So you can change the query like this.

   xdoc.Descendants().Where(d => d.Name.LocalName.Equals("rule") 
            && d.Descendants().Any(dd => dd.Name.LocalName.Equals("descr") && dd.Value.Equals("delete this"))).Remove();
Kosala W
  • 2,133
  • 1
  • 15
  • 20