0

The structure of my XML using XElement looks like this. I am using XElement in XDocument

<?xml version='1.0' encoding='UTF-8'?>
<return xmlns:rmas="" xmlns:xsi="" xsi:noNamespaceSchemaLocation="">
  <header>
    [...]
  </header>
  <body>
     <scheme>
        [...]
        <data>
          <serial-no>1</serial-no>
          <employment>1</employment>
          <code>1234</code>
        </data>
        <data />
        <data />
     </scheme>
     <scheme>
        [...]
        <data>
          <serial-no>1</serial-no>
          <employment>1</employment>
          <code>1234</code>
        </data>
        <data />
        <data />
     </scheme>
     <scheme>
        [...]
        <data>
          <serial-no>1</serial-no>
          <employment>1</employment>
          <code>1234</code>
        </data>
        <data />
        <data />
     </scheme>
  </body>
</return>

I'd like to remove all data elements with no child elements i.e <data /> elements. Here's my code

 foreach (XElement scheme in doc.Descendants("scheme"))
 {
            //copy an existing node as template for new data node.
            XElement newData = XElement.Parse(scheme.Element("data").ToString());
            newData.Element("serial-no").SetValue("abc1234");
            newData.Element("employment").SetValue("PUZAD-452");
            newData.Element("code").SetValue(codeValue);


            XElement newData2 = XElement.Parse(scheme.Element("data").ToString());
            newData2.Element("serial-no").SetValue("abc1234");
            newData2.Element("employment").SetValue("PUZAD-452");
            newData2.Element("code").SetValue(codeValue);


            XElement newData3 = XElement.Parse(scheme.Element("data").ToString());
            newData3.Element("serial-no").SetValue("abc1234");
            newData3.Element("employment").SetValue("PUZAD-452");
            newData3.Element("code").SetValue(codeValue);

            if (getGlobalScheme1 == "1111")
            {
                if ((string)(scheme.Descendants("code").First()) == "1111")
                {
                    newData2.RemoveAll();
                    newData3.RemoveAll();
                }
                scheme.Add(newData);
            }
            if (getGlobalScheme2 == "2222")
            {
                if ((string)(scheme.Descendants("code").First()) == "2222")
                {
                    newData.RemoveAll();
                    newData3.RemoveAll();
                }
                scheme.Add(newData2);
            }

            if (getGlobalScheme3 == "3333")
            {
                if ((string)(scheme.Descendants("code").Last()) == "3333")
                {
                    newData.RemoveAll();
                    newData2.RemoveAll();
                }
                scheme.Add(newData3);
            }
}

How do i achieve my goal of removing the <data /> elements with no child elements. I've been cracking my head around this but to no avail.

hopeforall
  • 401
  • 1
  • 6
  • 20
  • 1
    Does this answer your question? [how to remove Xelement without its children node using LINQ?](https://stackoverflow.com/questions/21730252/how-to-remove-xelement-without-its-children-node-using-linq) – Lucifer Mar 16 '20 at 12:23
  • 1
    Does this answer your question? [How to delete specific nodes from an XElement?](https://stackoverflow.com/questions/28169101/how-to-delete-specific-nodes-from-an-xelement) – vasilisdmr Mar 16 '20 at 12:27
  • Try following : List schemes in doc.Descendants("scheme"); for(int i = schemes.Count() - 1; i >= 0; i--){ scheme = schemes[i];} – jdweng Mar 16 '20 at 13:09
  • @Lucifer No it does not. I only want to remove the data element(s) only if it has no child elements – hopeforall Mar 16 '20 at 13:13
  • @hopeforall did you tried mine? – vasilisdmr Mar 16 '20 at 13:28
  • @vasilisdmr Same thing Sir. Would you like to help with a code snippet? – hopeforall Mar 16 '20 at 13:38
  • @jdweng Where should I place the code? – hopeforall Mar 16 '20 at 13:42
  • Instead of the foreach. When you delete an item from a list you have to delete from the end so you do not skip items. – jdweng Mar 16 '20 at 13:51

2 Answers2

0

I will try and answer that.

Try adding elements which have child into an array, then iterate over that.

Give the following a go, use it before the foreach statement:

    var nodes = doc.Descendants("scheme").Where(x => x.Element("data") != null).ToList();

Other than that you can try with the exact opposite logic, by checking if the node you are currently iterating has child with this code code snippet:

    YourXmlNode.ChildNodes.OfType<XmlElement>().Any()

I am also adding some links to articles and answers which I consider will help you figure out your problem.

vasilisdmr
  • 554
  • 8
  • 15
0

(1) Lets save your XML as a file on a file system.

(2) We'll create a List<XElement> list of SCHEME nodes.

(3) Iterate through list of SCHEME nodes and delete DATA elements without children.

(4) Save modified XML back to the file.

XML File

<?xml version="1.0" encoding="UTF-8"?>
<return xmlns:rmas="someURI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="fafa.xsd">
    <header>[...]</header>
    <body>
        <scheme>
            <data>
                <serial-no>1</serial-no>
                <employment>1</employment>
                <code>1234</code>
            </data>
            <data/>
            <data/>
        </scheme>
        <scheme>
            <data>
                <serial-no>1</serial-no>
                <employment>1</employment>
                <code>1234</code>
            </data>
            <data/>
            <data/>
        </scheme>
        <scheme>
            <data>
                <serial-no>1</serial-no>
                <employment>1</employment>
                <code>1234</code>
            </data>
            <data/>
            <data/>
        </scheme>
    </body>
</return>

c#

void Main()
{
    const string fileName = @"e:\Temp\Delete.xml";
    const string SCHEME = "scheme";
    const string DATA = "data";

    XDocument xdoc = XDocument.Load(fileName);

    // create list of SCHEME nodes
    List<XElement> nodes = xdoc.Descendants(SCHEME).ToList();

    // iterate through list of SCHEME nodes and delete DATA elements without children.
    foreach (XElement node in nodes)
        node.Elements(DATA).Where(n => n.DescendantNodes().Count() == 0).Remove();

    // end result
    Console.WriteLine(xdoc);

    // save back
//  xdoc.Save(fileName);
}

Output XML

<return xmlns:rmas="someURI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="fafa.xsd">
    <header>[...]</header>
    <body>
        <scheme>
            <data>
                <serial-no>1</serial-no>
                <employment>1</employment>
                <code>1234</code>
            </data>
        </scheme>
        <scheme>
            <data>
                <serial-no>1</serial-no>
                <employment>1</employment>
                <code>1234</code>
            </data>
        </scheme>
        <scheme>
            <data>
                <serial-no>1</serial-no>
                <employment>1</employment>
                <code>1234</code>
            </data>
        </scheme>
    </body>
</return>
Yitzhak Khabinsky
  • 18,471
  • 2
  • 15
  • 21