Reputation: 339
I have this XML:
<Meals>
<Meal>
<Food course="starter">Soup</Food>
<Food course="mains">Fish</Food>
<Food course="dessert">Ice cream</Food>
</Meal>
<Meal>
<Food course="starter">Soup</Food>
<Food course="mains">Chicken</Food>
<Food course="dessert">Cheese</Food>
</Meal>
<Meal>
<Food course="starter">Melon</Food>
<Food course="mains">lamb</Food>
<Food course="dessert">Ice cream</Food>
</Meal>
</Meals>
And this XPath expression:
//Food[@course='dessert' and text() = 'Ice cream']
This finds every dessert course of ice cream. I want to add a new element after each matching element like so:
<Meals>
<Meal>
<Food course="starter">Soup</Food>
<Food course="mains">Fish</Food>
<Food course="dessert">Ice cream</Food>
<Review>enjoyed</Food>
</Meal>
<Meal>
<Food course="starter">Soup</Food>
<Food course="mains">Chicken</Food>
<Food course="dessert">Cheese</Food>
</Meal>
<Meal>
<Food course="starter">Melon</Food>
<Food course="mains">lamb</Food>
<Food course="dessert">Ice cream</Food>
<Review>enjoyed</Food>
</Meal>
</Meals>
How can I do this in C# given that XPath expression? The expression may alter (for example selecting mains instead), and the structure of the XML may vary too. Regardless a new element must be inserted after each matching element.
I know there is a AddAfterSelf method on an XElement, but I don't know how to use that on the collection of XElements the XPath expression may return.
Upvotes: 0
Views: 96
Reputation: 1882
And this XPath expression:
//Food[@course='dessert' and text() = 'Ice cream']
This finds every Meal that has a dessert course of ice cream. I want to add a new element after each matching element like so:
That expression is wrong. You need:
/Meals/Meal[Food[@course = 'dessert'] = 'Ice cream']
Upvotes: 0
Reputation: 339
It's straightforward, but I needed a reminder from @Fabio that a foreach is what is necessary:
foreach (var element in foodXml.XPathSelectElements(xpathExpression))
{
element.AddAfterSelf(new XElement($"Review", "enjoyed"));
}
foodXml now has the additional enjoyed element after the matching elements
Upvotes: 1
Reputation: 32455
LINQ to XML
var doc = XDocument.Parse("filepath");
var enjoyedMeals =
doc.Descendants("Meal")
.Where(meal => meal.Elements.Any(food => food.Attribute("course").Value == "desert"));
foreach (var meal in enjoyedMeals)
{
var review = new XElement("Review", "enjoyed");
meal.Elements.Add(review);
}
doc.ToString(); // contains <Review> elements
Upvotes: 1