从C#中的对象列表更新XML节点

时间:2014-08-25 06:52:29

标签: c# xml linq linq-to-xml

我有一个具有以下结构的XML文件:

<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>

我有一个程序,它接受这些值并创建一个列表&#39;项目&#39;称为&#39; stockArray&#39;的对象。每个项目都有一个int-Id(来自recordNumber)和一个int-count(来自stock)。

该程序更新&#34; stock&#34;相应的值和我想要做的是然后更新XML文件以获得新的&#39; stock&#39;值。

我是C#和XML的新手,所以这就是我一直走下去的路径:

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));
    }
}

但到目前为止,这似乎已经过时了。我可以找到很多关于向XML添加新节点的信息,但是遍历stockArray项列表并更新XML似乎是一个不同的过程。

非常感谢任何建议。

4 个答案:

答案 0 :(得分:2)

您的XML没有<count>元素。如果您要更新<stock>元素值,SetElementValue()的第一个参数应为"stock"

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

使用LINQ连接创建匿名类型的一种可能方式,将<product>元素与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);
}

答案 1 :(得分:0)

试试这个,但你会想要对空值进行一些错误处理。

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();
   }

编辑:修复代码!

答案 2 :(得分:0)

您正在修改count元素而不是stock元素。

并提高性能(这里的复杂性是O(n ^ 2))。您可以从stockArray创建字典。

创建字典的复杂度为O(n)。 在字典中获取值的复杂度为O(1)。

因此,使用字典的程序的复杂性是O(n)。

我还建议您使用explicit castXElement的值转换为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);
}

答案 3 :(得分:0)

您可以使用XmlSerializer执行此操作。唯一的事情是你必须把你的xml结构写成类。请参阅代码示例。

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; }
}