user20358
user20358

Reputation: 14736

Querying XML and updating certain elements

I have an XML file in the following format

<?xml version="1.0" ?>
<AA someattrib="xyz">
    <BB someOtherAttrib="xyz">
    <Title></Title>
        <CC>

            <myNode rowid="">
                <subNode1></subNode1>
                <subNode2></subNode2>
                <nodeOfInterest></nodeOfInterest>
            </myNode >
            <myNode rowid="">
                <subNode1> </subNode1>

            </myNode>
        </CC>
    </BB>
</AA>

I want to use Linq to pick out one node by the name 'MyNode' where the rowid is a particular number that I will be getting from a collection in an object. Once I get myNode I want to update the value of the child nodeOfInterest if it is present. If not present, then I would like to add it. Once done I want to save the file.

This is what I have at the moment but it may not be the right approach.

    foreach (User employee in Users)
    {

        XPathNavigator node = xNav.SelectSingleNode("/AA/BB/CC/myNode[@rowid = '"+employee.ID.ToString()+"']");
        XPathNodeIterator nodeIterator= node.SelectChildren("nodeOfInterest", "");
        if (nodeIterator.Count == 1)
        {

        }
        else
        {
        }

    }

Is there a way this can be done using a direct join between the List and the xmldoc in memory? This will be a large list and an equally large xml file. I dont think running a loop and calling selectSingleNode is the most efficient way.

Thanks for your inputs

Upvotes: 0

Views: 86

Answers (2)

user20358
user20358

Reputation: 14736

The full answer, with help from Jon's replies...

var doc = XDocument.Load("thefile.xml");
var dictionary = doc.Element("AA").Element("BB").Element("CC").Elements("myNode")
                .ToDictionary(x => x.Attribute("rowId").Value);

foreach (User employee in Users)
{
    XElement myNode;
    if (dictionary.TryGetValue(employee.ID, out myNode))
    {
            XElement nodeOfInterest = myNode.Elements("nodeOfInterest").FirstOrDefault();
            if (nodeOfInterest != null)
            {
                nodeOfInterest.Value = "update with this value";
            }
            else
            {
                XElement nodeOfInterest = new XElement("nodeOfInterest", "Add nodeOfInterest with this value");
                myNode.Add(newElement);
            }
    }

}
doc.Save("TheFile.xml");

Upvotes: 0

Jon Skeet
Jon Skeet

Reputation: 1499770

Well one starting point would be to create a Dictionary<string, XElement> mapping the row ID to the element:

var dictionary = doc.Element("AA").Element("BB").Element("CC").Elements("myNode")
                    .ToDictionary(x => x.Attribute("rowId").Value);

Then:

foreach (User employee in Users)
{
    XElement myNode;
    if (dictionary.TryGetValue(employee.ID, out myNode))
    {
        // Use myNode
    }
    else
    {
        // Employee not found
    }
}

Personally I prefer using the selection methods provided by LINQ to XML (Elements, Element, Descendants etc) rather than SelectSingleNode, SelectChildren etc.

Upvotes: 2

Related Questions