Daviepark
Daviepark

Reputation: 65

Updating XML nodes from an object list in C#

I have an XML file with this structure:

<inventory>
<product>
    <recordNumber>1</recordNumber>
    <name>Dustbin</name>
    <stock>190</stock>
    <price>33</price>
</product>
<product>
    <recordNumber>2</recordNumber>
    <name>Broom</name>
    <stock>200</stock>
    <price>76</price>
</product>

</inventory>

I have a program which takes in these values and creates a List of 'Item' objects called 'stockArray'. each item has an int-Id(from recordNumber) and an int-count(from stock).

The program updates the "stock" value accordingly and what I am looking to do is then update the XML file to have the new 'stock' value.

I am very new to C# and XML, so this is the path I have been going down:

XDocument doc = XDocument.Load(xml);

var list = doc.Element("inventory").Elements("product");

foreach (var node in list)
{
    foreach (Item item in stockArray)
    {
        if (node.Element("recordNumber").Value == Convert.ToString(item.Id))
            node.SetElementValue("count", Convert.ToString(item.count));
    }
}

But so far this seems way off course. I can find a lot of information about adding new nodes to an XML but iterating through the stockArray item list and updating the XML seems to be a different process.

Any advice would be greatly appreciated.

Upvotes: 0

Views: 2432

Answers (4)

C&#233;dric Bignon
C&#233;dric Bignon

Reputation: 13022

You are editing the count element instead of stock element.

And to improve performance (here the complexity is O(n^2)). You can create a dictionary from the stockArray.

Creating the dictionary has a complexity of O(n). And getting a value in the dictionary has a complexity of O(1).

So, the complexity of the program with the dictionary is O(n).

I would also suggest you to use the explicit cast to convert the value of the XElement to int.

XDocument doc = XDocument.Load(xml);

var list = doc.Element("inventory").Elements("product");
var stockDictionary = stockArray.ToDictionary(item => item.Id, item => item.Count);

foreach (var node in list)
{
    int newCount;
    if (if(stockDictionary.TryGetValue((int)node.Element("recordNumber"), out newCount)
        node.SetElementValue("stock", newCount);
}

Upvotes: 0

Seminda
Seminda

Reputation: 1773

You can use XmlSerializer to do this. Only thing is you have to write your xml structure as classes. see the code sample.

class Program
{
    static void Main(string[] args)
    {
        // Create a new file stream for reading the XML file
        FileStream ReadFileStream = new FileStream(@"C:\files\data.xml", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);

        // Load the object saved above by using the Deserialize function
        Inventory LoadedObj = (Inventory)SerializerObj.Deserialize(ReadFileStream);

        // Cleanup
        ReadFileStream.Close();

        foreach (var node in LoadedObj.Products)
        {
             // node.Stock = 0;
            //Do what ever changes to stock
        }

        XmlSerializer SerializerObj = new XmlSerializer(typeof(Inventory));
        //// Create a new file stream to write the serialized object to a file
        TextWriter WriteFileStream = new StreamWriter(@"C:\files\data.xml");
        SerializerObj.Serialize(WriteFileStream, TestObj);
        //// Cleanup
        WriteFileStream.Close();


    }
}


[System.SerializableAttribute()]
[System.Xml.Serialization.XmlRoot("inventory")]
public class Inventory
{
    [System.Xml.Serialization.XmlElement("product")]
    public List<Product> Products { get; set; }

}

[System.SerializableAttribute()]

   public class Product
{
    [System.Xml.Serialization.XmlElementAttribute("recordNumber")]
    public string RecordNumber { get; set; }
    [System.Xml.Serialization.XmlElementAttribute("name")]
    public string Name { get; set; }
    [System.Xml.Serialization.XmlElementAttribute("stock")]
    public int Stock { get; set; }
    [System.Xml.Serialization.XmlElementAttribute("price")]
    public int Price { get; set; }
}

Upvotes: 0

har07
har07

Reputation: 89285

Your XML doesn't have <count> element. If you meant to update <stock> element value, the first parameter of SetElementValue() should be "stock" :

if (node.Element("recordNumber").Value == Convert.ToString(item.Id))
    node.SetElementValue("stock", Convert.ToString(item.count));

One possible way using LINQ join to create anonymous type that pair <product> element with the corresponding item from stockArray :

var list = from product in doc.Element("inventory").Elements("product")
           join item in stockArray on (int)product.Element("recordNumber") equals item.id
           select new {product = product, item = item};
foreach (var joinedProduct in list)
{
    joinedProduct.product.SetElementValue("stock", joinedProduct.item.count);
}

Upvotes: 2

Ray Suelzer
Ray Suelzer

Reputation: 4107

Try this, but you will want to do some error handling for null values.

var doc = XDocument.Load(xml);
var list = doc.Element("inventory").Elements("product");

 foreach (var item in stockArray)
   {
   var node = list.FirstOrDefault(p => p.Element("recordNumber").Value == item.ToString());
            node.Element("stock").Value = item.Count.ToString();
   }

Edit: fixing the code!

Upvotes: 0

Related Questions