Manipulate XML content and persist changes using Linq

Description
Table of Contents
Description

The following XML document is used in the operations section:

<contacts>
  <contact contactId="1">
    <firstName>João</firstName>
    <lastName>Seixas</lastName>
    <addresses>
      <address type="home">
        <street>street 1</street>
        <city>Funchal</city>
        <region>Madeira</region>
        <zip>9020-402</zip>
      </address>
      <address type="work">
        <street>street 1 tecnopolo</street>
        <city>Funchal</city>
        <region>Madeira</region>
        <zip>9020-420</zip>
      </address>
    </addresses>
  </contact>
  <contact contactId="2">
    <firstName>Ana</firstName>
    <lastName>Travassos</lastName>
    <addresses>
      <address type="home">
        <street>street 2</street>
        <city>Funchal</city>
        <region>Madeira</region>
        <zip>9010-402</zip>
      </address>
      <address type="work">
        <street>street 2 tecnopolo</street>
        <city>Funchal</city>
        <region>Madeira</region>
        <zip>9010-420</zip>
      </address>
    </addresses>
  </contact>
    <contact contactId="3">
    <firstName>José</firstName>
    <lastName>Travassos</lastName>
    <address type="home">
        <street>street 3</street>
        <city>Funchal</city>
        <region>Madeira</region>
        <zip>9030-402</zip>
    </address>
    <address type="work">
        <street>street 3 tecnopolo</street>
        <city>Funchal</city>
        <region>Madeira</region>
        <zip>9030-420</zip>
    </address>
  </contact>
</contacts>

 

Operations
Change element within a XML document
How to do it
XElement xdoc = XElement.Load("Test.xml")

IEnumerable<XElement> elements = xdoc.Elements()

foreach (
  XElement item in elements.Elements("firstName").Where(e => e.Value == "João"))
{
	item.Value = "José"
}

/* Alternative method

var query = from c in xelement.Elements("contact")
            where c.Element("firstName").Value == "João"
	    select c;

foreach (XElement item in query)
{
	item.Element("firstName").Value = "José"
}
*/

xdoc.Save("Test.xml");
Change attribute within a XML document
How to do it
XElement xdoc = XElement.Load("Test.xml")

IEnumerable<XElement> elements = xdoc.Elements()

foreach (
  XAttribute item in elements.Attributes("firstName").Where(e => e.Value == "João"))
{
	item.Value = "José"
}

xdoc.Save("Test.xml");
Remove element within a XML document
How to do it
XElement xdoc = XElement.Load("Test.xml")

IEnumerable<XElement> elements = xdoc.Elements()

//Remove element <contact> where child element “firstName” equal to “João”
elements.AncestorsAndSelf("contact")
	.Where(e => e.Element("firstName").Value == "João")
	.Remove()

/* if attribute instead, remove element <contact> where attribute “firstName” equal to “João”
elements.AncestorsAndSelf("contact")
	.Where(e => e.Attribute("firstName").Value == "João")
	.Remove()
*/

xdoc.Save("Test.xml");
Insert element to the end of a XML document
How to do it
XElement xdoc = Xelement.Load("Test.xml")

//Add element as the last child element of the XML document
xdoc.Add(new XElement("contact",
                        new XAttribute("contactId", "3"),
                        new XElement("firstName", "José"),
                        new XElement("lastName", "Seixas")));

xdoc.Save("Test.xml");
Insert element as the first child of a XML document
How to do it
XElement xdoc = Xelement.Load("Test.xml")

//Add element as the last child element of the XML document
xdoc.AddFirst(new XElement("contact",
                        new XAttribute("contactId", "3"),
                        new XElement("firstName", "José"),
                        new XElement("lastName", "Seixas")));

xdoc.Save("Test.xml");
Find element at specific position within a XML document
How to do it
// Find element using XElement

XElement xelement = XElement.Load("Test.xml");
var contact1 = xelement.Descendants("contact").ElementAt(1);
Console.WriteLine(contact1);

// Find element when using XDocument

XDocument xdoc = XDocument.Load("Test.xml");
var contact1 = xdoc.Descendants("contact").ElementAt(1);
Console.WriteLine(contact1);
List the first N elements of a XML document
How to do it
XElement xdoc = XElement.Load("Test.xml");
var contacts = xdoc.Descendants("contact").Take(2);

foreach (var item in contacts)
    Console.WriteLine(item);
List N elements of a XML document (after the first M child elements)
How to do it
// List the 2nd and 3rd elements

XElement xdoc = XElement.Load("Test.xml");
var contacts = xdoc.Descendants("contact").Skip(1).Take(2);

foreach (var item in contacts)
    Console.WriteLine(item);
List N last elements of a XML document
How to do it
// List last two elements

XElement xdoc = XElement.Load("Test.xml");

var contacts = xdoc.Descendants("contact").Reverse().Take(2);

foreach (var item in contacts)
    Console.WriteLine(item);
Replace contents of an element or element(s) of a XML document
How to do it
// List last two elements

// Replace country node element value...
var countries = xdoc.Elements("contact").Elements("address").Elements("country").ToList();

foreach (XElement item in countries)
        item.ReplaceNodes("Portugal");

Console.Write(xdoc);
Remove an attribute from all elements of the XML document
How to do it
XElement xdoc = XElement.Load("Test.xml");
var addresses = xdoc.Elements("contact").Elements("address").ToList();

foreach (XElement item in addresses)
        item.RemoveAttributes();
Remove an element from a XML document
How to do it
XElement xdoc = XElement.Load("Test.xml");
var contacts = xdoc.Elements("contact").ToList();

foreach (XElement item in contacts)
	item.SetElementValue("address", null);
Filter specific XML node by node name
How to do it
string lvValue = element.Nodes.Single(n => n.LocalName == "address").InnerXml;
Filter XML nodes and build another XML document
How to do it
XDocument xdoc = XDocument.Load("Test.xml");

XElement root = new XElement("SiteMenuItems",
                    (
                       from c in xdoc.Descendants("contact")
                       where c.Element("lastName").Value == "Seixas"
                       select new XElement(c))
                    );

XDocument doc2 = new XDocument();
doc2.Add(root);
<contacts>
  <contact contactId="1">
    <firstName>João</firstName>
    <lastName>Seixas</lastName>
    <address type="home">
        <street>street 1</street>
        <city>Funchal</city>
        <region>Madeira</region>
        <zip>9020-402</zip>
    </address>
    <address type="work">
        <street>street 1 tecnopolo</street>
        <city>Funchal</city>
        <region>Madeira</region>
        <zip>9020-420</zip>
    </address>
  </contact>
  <contact contactId="3">
    <firstName>José</firstName>
    <lastName>Seixas</lastName>
    <address type="home">
        <street>street 3</street>
        <city>Funchal</city>
        <region>Madeira</region>
        <zip>9030-402</zip>
    </address>
    <address type="work">
        <street>street 3 tecnopolo</street>
        <city>Funchal</city>
        <region>Madeira</region>
        <zip>9030-420</zip>
    </address>
  </contact>
</contacts>