Tomato <" /> Tomato <" /> Tomato <"/>

Merging the XElement Parent-Child Name and Value Programmatically using Linq to Xml

25 views Asked by At

From this XML with around 10,000 records:

    <?xml version="1.0" encoding="utf-8"?>
    <Home>
       <Kitchen>
          <Pantry>
             <Ingredients>
                <Name>Tomato</Name>
                <Price>
                   <ID>1</ID>
                   <Name>SALES</Name>
                </Price>
                <Cost>
                   <ID>2</ID>
                   <Name>COGS</Name>
                </Cost>
              </Ingredients>
           </Pantry>
        </Kitchen>
    </Home>

I was able to manually code the merging of the parent-child (Price and Cost above) name and values with below code:

    // source programmatically generated
    XElement xml = XElement.Parse(xml.ToString());

    foreach (XElement el in xQuery.Descendants("Price"))
    {
        XElement id = el.Element("ID");
        id.ReplaceWith(new XElement("Price_ID", el.Element("ID").Value));
    
        XElement name = el.Element("Name");
        name.ReplaceWith(new XElement("Price_Name", el.Element("Name").Value));
    
        XElement Price_ID = el.Element("Price_ID");
        XElement Price_Name = el.Element("Price_Name");
    
        el.AddBeforeSelf(Price_ID);
        el.AddBeforeSelf(Price_Name);
    }

    foreach (XElement el in xQuery.Descendants("ItemInventoryRet"))
    {
        if (el.Element("Price") != null)
        {
            XElement Price= el.Element("Price");
            Price.Remove();
        }
    }

    // same manual procedure for Cost element..

The desired result:

    <?xml version="1.0" encoding="utf-8"?>
    <Home>
       <Kitchen>
          <Pantry>
             <Ingredients>
                <Name>Tomato</Name>
                <Price_ID>1</Price_ID>
                <Price_Name>SALES</Price_Name>
                <Cost_ID>2</Cost_ID>
                <Cost_Name>COGS</Cost_Name>
              </Ingredients>
           </Pantry>
        </Kitchen>
    </Home>

Now, I am trying to replicate programmatically the above manual code, and here's what I have so far, please note my error below:

    // source programmatically generated
    XElement xml = XElement.Parse(xml.ToString());

    foreach (XElement xParent in xQuery.Descendants("Ingredients").Nodes())
    {
        if (xParent.HasElements)
        {
            string parentName = xParent.Name.ToString();
    
            foreach (XElement xChild in xParent.DescendantsAndSelf(xParent.Name).Nodes())
            {
                string childName = xChild.Name.ToString();
                string concatName = xParent.Name.ToString() + "_" + xChild.Name.ToString();
    
                XElement child = xChild.Element(childName);
    
                xChild.ReplaceWith(new XElement(concatName, xChild.Value.ToString())); // error here: System.NullReferenceException: 'Object reference not set to an instance of an object.'
                XElement concatElement = xChild.Element(concatName);
                xChild.AddBeforeSelf(concatElement); 
            }
    
            if (xParent.Element(parentName) != null)
            {
                XElement parentEl = xParent.Element(parentName);
                parentEl.Remove();
            }
        }
    }

I am getting an error System.NullReferenceException: 'Object reference not set to an instance of an object.' at child.ReplaceWith() above.

0

There are 0 answers