Reputation: 65
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
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
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
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
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