user12081690
user12081690

Reputation:

LINQ Modify XML document

I need to modify an XML file containing product sales. I tried to do this with LINQ, however it doesn't work. I have the following file

<SalesProducts>
    <ProductSale>
        <Sale type="Fixed">
        <ProductId>22</ProductId>
        <Value>50</Value>
    </ProductSale>
    <ProductSale>
        <Sale type="Discount">
        <ProductId>32</ProductId>
        <Value>33</Value>
    </Product>
</SalesProducts>

I want to add another ProductSale item after the item where product id is equal to 22.

I tried the following query.

var elProd = docX.Element("SalesProducts").
    Elements("ProductSale").
    Where(e => ((string)e.Element("ProductId")) == "22");

elProd.AddAfterSelf(
    new XElement("Sale", ""),
    new XElement("Value", "43"),
    new XElement("ProductId", "154")));

But this doesn't work. Also I can't add attribute to Sale element.

Any help is highly appreciated.

Upvotes: 1

Views: 63

Answers (2)

Anu Viswan
Anu Viswan

Reputation: 18163

elProd is a Collection of XElement. This is the reason you are not able to use elProd.AddAfterSelf as the method is defined for XElement and not for IEnumerable<XElement>.

Since you are searching for specific Product, you could use Single()(Assuming there is no duplicate ProductID) to ensure only the desired element is selected.

var elProd = docX.Element("SalesProducts")
                 .Elements("ProductSale")
                 .Single(e => ((string)e.Element("ProductId") == "22"));

Or

var elProd = docX.Descendants("ProductSale")
                 .Single(e => ((string)e.Element("ProductId") == "22"));

Once you have selected the desired element, you can now use AddAfterSelf to add the new Element. Please note you need to create an XElement ProductSale, with Sale/Value/ProductID as child.

elProd.AddAfterSelf(new XElement("ProductSale",
            new XElement("Sale", new XAttribute("type", "Type of sale")),
            new XElement("Value", "43"),
            new XElement("ProductId", "154")));

Output Sample

<SalesProducts>
  <ProductSale>
    <Sale type="Fixed"></Sale>
    <ProductId>22</ProductId>
    <Value>50</Value>
  </ProductSale>
  <ProductSale>
    <Sale type="Type of sale" />
    <Value>43</Value>
    <ProductId>154</ProductId>
  </ProductSale>
  <ProductSale>
    <Sale type="Discount"></Sale>
    <ProductId>32</ProductId>
    <Value>33</Value>
  </ProductSale>
</SalesProducts>

Upvotes: 2

JohnyL
JohnyL

Reputation: 7152

You could use overload of First method:

var first = xml.Elements().First(n => n.Element("ProductId").Value == "22");
first.AddAfterSelf(XElement.Parse(@"<ProductSale><Sale type='Discount'/><Value>43</Value><ProductId>154</ProductId></ProductSale>"));

Upvotes: 1

Related Questions