XDocument and the System.Xml.Linq namespace
Generate an XML document
The goal is to generate the following XML document:
<FruitBasket xmlns="https://www.fruitauthority.fake">
<Fruit ID="F0001">
<FruitName>Banana</FruitName>
<FruitColor>Yellow</FruitColor>
</Fruit>
<Fruit ID="F0002">
<FruitName>Apple</FruitName>
<FruitColor>Red</FruitColor>
</Fruit>
</FruitBasket>
Code:
XNamespace xns = "https://www.fruitauthority.fake";
XDeclaration xDeclaration = new XDeclaration("1.0", "utf-8", "yes");
XDocument xDoc = new XDocument(xDeclaration);
XElement xRoot = new XElement(xns + "FruitBasket");
xDoc.Add(xRoot);
XElement xelFruit1 = new XElement(xns + "Fruit");
XAttribute idAttribute1 = new XAttribute("ID", "F0001");
xelFruit1.Add(idAttribute1);
XElement xelFruitName1 = new XElement(xns + "FruitName", "Banana");
XElement xelFruitColor1 = new XElement(xns + "FruitColor", "Yellow");
xelFruit1.Add(xelFruitName1);
xelFruit1.Add(xelFruitColor1);
xRoot.Add(xelFruit1);
XElement xelFruit2 = new XElement(xns + "Fruit");
XAttribute idAttribute2 = new XAttribute("ID", "F0002");
xelFruit2.Add(idAttribute2);
XElement xelFruitName2 = new XElement(xns + "FruitName", "Apple");
XElement xelFruitColor2 = new XElement(xns + "FruitColor", "Red");
xelFruit2.Add(xelFruitName2);
xelFruit2.Add(xelFruitColor2);
xRoot.Add(xelFruit2);
Modify XML File
To modify an XML file with XDocument
, you load the file into a variable of type XDocument
, modify it in memory, then save it, overwriting the original file.
A common mistake is to modify the XML in memory and expect the file on disk to change.
Given an XML file:
<?xml version="1.0" encoding="utf-8"?>
<FruitBasket xmlns="https://www.fruitauthority.fake">
<Fruit>
<FruitName>Banana</FruitName>
<FruitColor>Yellow</FruitColor>
</Fruit>
<Fruit>
<FruitName>Apple</FruitName>
<FruitColor>Red</FruitColor>
</Fruit>
</FruitBasket>
You want to modify the Banana’s color to brown:
-
We need to know the path to the file on disk.
-
One overload of
XDocument.Load
receives a URI (file path). -
Since the xml file uses a namespace, we must query with the namespace AND element name.
-
A Linq query utilizing C# 6 syntax to accommodate for the possibility of null values. Every
.
used in this query has the potential to return a null set if the condition finds no elements. Before C# 6 you would do this in multiple steps, checking for null along the way. The result is the<Fruit>
element that contains the Banana. Actually anIEnumerable<XElement>
, which is why the next step usesFirstOfDefault()
. -
Now we extract the FruitColor element out of the Fruit element we just found. Here we assume there is just one, or we only care about the first one.
-
If it is not null, we set the FruitColor to “Brown”.
-
Finally, we save the
XDocument
, overwriting the original file on disk.// 1. string xmlFilePath = “c:\users\public\fruit.xml”;
// 2. XDocument xdoc = XDocument.Load(xmlFilePath);
// 3. XNamespace ns = ”https://www.fruitauthority.fake“;
//4. var elBanana = xdoc.Descendants()?. Elements(ns + “FruitName”)?. Where(x => x.Value == “Banana”)?. Ancestors(ns + “Fruit”);
// 5. var elColor = elBanana.Elements(ns + “FruitColor”).FirstOrDefault();
// 6. if (elColor != null) { elColor.Value = “Brown”; }
// 7. xdoc.Save(xmlFilePath);
The file now looks like this:
<?xml version="1.0" encoding="utf-8"?>
<FruitBasket xmlns="https://www.fruitauthority.fake">
<Fruit>
<FruitName>Banana</FruitName>
<FruitColor>Brown</FruitColor>
</Fruit>
<Fruit>
<FruitName>Apple</FruitName>
<FruitColor>Red</FruitColor>
</Fruit>
</FruitBasket>
Generate an XML document using fluent syntax
Goal:
<FruitBasket xmlns="https://www.fruitauthority.fake">
<Fruit>
<FruitName>Banana</FruitName>
<FruitColor>Yellow</FruitColor>
</Fruit>
<Fruit>
<FruitName>Apple</FruitName>
<FruitColor>Red</FruitColor>
</Fruit>
</FruitBasket>
Code:
XNamespace xns = "https://www.fruitauthority.fake";
XDocument xDoc =
new XDocument(new XDeclaration("1.0", "utf-8", "yes"),
new XElement(xns + "FruitBasket",
new XElement(xns + "Fruit",
new XElement(xns + "FruitName", "Banana"),
new XElement(xns + "FruitColor", "Yellow")),
new XElement(xns + "Fruit",
new XElement(xns + "FruitName", "Apple"),
new XElement(xns + "FruitColor", "Red"))
));