You can generate your XML into memory dynamically or loading from XML file, as sample below shown
XElement element = new XElement("Order",
new XElement("orderid","001"),
new XElement("quantity",10),
new XElement("price",50)
);
It will display
<Order>
<orderid>001</orderid>
<quantity>10</quantity>
<price>50</price>
</Order>
You can also calculate value among elements, for example calculating total amount in one order as below :
decimal totalPrice = (int)element.Element("quantity") * (decimal)element.Element("price");
It returns result 500
You need to implement namespace into XML. Namespace is useful in various scenario, one of them is to validate XML content against XML schema. XML namespace is declared in XNamespace class, as below :
XNamespace ns = "http://www.test.com/Customers";
And put namespace inside the XML element content like below :
XElement customers = new XElement (
ns+"customers",
new XElement(ns + "customer",
new XAttribute("firstname", "john"),
new XAttribute("lastname", "grisham")
),
new XElement(ns + "customer",
new XAttribute("firstname", "alex"),
new XAttribute("lastname", "good")
)
);
It will display output :
<customers xmlns="http://www.test.com/Customers">
<customer firstname="john" lastname="grisham" />
<customer firstname="alex" lastname="good" />
</customers>
You can add alias for XML namespace to the content.
XElement customers = new XElement (
ns+"customers",
new XAttribute(XNamespace.Xmlns+"c" , ns),
new XElement(ns + "customer",
new XAttribute("firstname", "john"),
new XAttribute("lastname", "grisham")),
new XElement(ns + "customer",
new XAttribute("firstname", "alex"),
new XAttribute("lastname", "good")
)
);
It will display the following result :
<c:customers xmlns:c="http://www.test.com/Customers">
<c:customer firstname="john" lastname="grisham" />
<c:customer firstname="alex" lastname="good" />
</c:customers>
Other useful class is Annotation. For XML, annotation is more like attribute in a class.
You can create a class as below :
public class CustomerNote
{
public string Notes;
}
Then you can create instance of CustomerNote and add it to XElement instance, later then you can retrieve back the annotation object and extract its property to display to the screen, see below code:
CustomerNote note = new CustomerNote { Notes = "just dummy notes" };
customers.AddAnnotation(note);
///retrieve back the object and extract value from its property
Console.WriteLine(customers.Annotation<CustomerNote>().Notes);
You can change XML element for example replace a element with its content, or change its element/attribute value with method ReplaceWith, SetAttributeValue, and SetElementValue. Feel free to see the content after change with Console.WriteLine(customers); here is the sample of ReplaceWith method
Sample of ReplaceWith method :
customers.LastNode.ReplaceWith(new XElement(ns+"customer",
new XAttribute("firstname","alexander"),
new XAttribute("lastname","good"),"Alexander"));
You can output the result into XML form from collection type object, for example :
public enum Countries{
USA,
Indonesia
}
public class Customer
{
public Countries Country;
public string Name;
public string City;
}
Then in Main static method of client console program, you create array of customers:
Customer[] customers = {
new Customer{ City="Jakarta", Country=Countries.Indonesia, Name="Anton"},
new Customer{ City="Bali", Country=Countries.Indonesia, Name="Budi"},
new Customer{ City="Wichita", Country=Countries.USA, Name="Inga"},
new Customer{ City="New York", Country=Countries.USA, Name="John"},
new Customer{ City="Florence", Country=Countries.USA, Name="George"}
};
var result =
new XElement("customers",
from c in customers
where c.Country == Countries.Indonesia
select new XElement(
new XElement("customer"
, new XAttribute("city",c.City)
, c.Name
)
)
);
The output is :
<customers>
<customer city="Jakarta">Anton</customer>
<customer city="Bali">Budi</customer>
</customers>
You can also query from xml file with LINQ, here the XML content structure :
<?xml version="1.0" encoding="utf-8" ?>
<customers>
<customer name="..." city="..." country="...." />
<customer name="..." city="..." country="...." />
.........
</customers>
XElement element = XElement.Load(@"c:\mycustomer.xml");
var result = from item in element.Elements("customer")
where (string)item.Attribute("country") == "Indonesia"
orderby (string)item.Attribute("name")
select new
{
Name = (string)item.Attribute("name"),
City = (string)item.Attribute("city")
};
The return type is IEnumerable<XElement>
You can also do querying between XML and object like this query below :
var result = from item in element.Elements("customer")
join o in orders
on (string)item.Attribute("Name") equals o.CustomerName
orderby (string)item.Attribute("Name")
select new
{
Name = (string)item.Attribute("Name"),
City = (string)item.Attribute("City"),
IdProduct = o.IdProduct,
Quantity = o.Quantity
};
Before you try above example, try to make dummy class Orders and array instance of order like this code below :
public class Order
{
public int OrderID;
public string CustomerName;
public int Quantity;
public int IdProduct;
}
And this one:
Order[] orders = {
new Order{ IdProduct=1, CustomerName="....", OrderID = 1, Quantity=10},
new Order{ IdProduct=2, CustomerName="....", OrderID = 2, Quantity=20}
};
You can replace repetitive explicit casting as you can see in (string)item.Attribute("Name") and (string)item.Attribute("City") with alias for each of them, so the query can be written as below:
var result = from item in element.Elements("customer")
let xName = (string)item.Attribute("name")
let xCity = (string)item.Attribute("city")
join o in orders
on xName equals o.CustomerName
orderby xName
select new
{
Name = xName,
City = xCity,
IdProduct = o.IdProduct,
Quantity = o.Quantity
};
In XML transformation with XSL, LINQ to XML also work with System.Xml.Xsl.XslCompiledTranform class to do transformation. XslCompiledTransform requires XPathNavigator class that exists in System.Xml.XPath. You can get the navigator instance from extension method CreateNavigator either from XmlDocument, XDocument or XElement. Here is the example.
XElement customers = XElement.Load(@"c:\mycustomer.xml");
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(@"c:\myxslt.xslt");xslt.Transform(customers.CreateNavigator(), null, Console.Out);
You can create XSLT from any XML tool including Visual Studio. With XPath, you can also do filtering with extension method XPathEvaluate.
For example, filtering only customer from Indonesia.
XElement result = new XElement(
"customers",
from c in customers
select new XElement
(
"customer",
new XAttribute("name", c.Name),
new XAttribute("city", c.City),
new XAttribute("country", c.Country)
)
);
Console.WriteLine(result.ToString());
Console.WriteLine();
var filter = (IEnumerable<object>)result.XPathEvaluate("/customer[@country='Italy']/@name");
foreach (var item in filter)
{
Console.WriteLine(item);
}
Because XPathEvaluate return object, you need to do explicit cast to IEnumerable<object>.
Other method is XPathSelectElement and XPathSelectElements, XPathSelectElement only return XElement type, whereas XPathSelectElements return IEnumerable<XElement>, so you can filter on XML nodes that returning IEnumerable<XElement> and you can join to IEnumerable<object> to return desired result. Here is the example :
XElement customers = XElement.Load(@"c:\mycustomer.xml");
var result = from c in customers.XPathSelectElements("/customer[@country='Indonesia']")
let xName = (string)c.Attribute("name")
let xCity = (string)c.Attribute("city")
let xCountry = (string)c.Attribute("country")
join o in orders
on xName equals o.CustomerName
orderby xName
select new
{
Name = xName,
City = xCity,
Country = xCountry,
IdProduct = o.IdProduct,
Quantity = o.Quantity
};
foreach (var item in result)
{
Console.WriteLine(item);
}