Using Namespaces
XML documents support namespaces. For example, if you add the following namespace to the XML file in Listing One (right after the <xml> tag -- both are shown), you need to include the namespace in both your LINQ-to-XML and your XPath queries.
<?xml version="1.0" encoding="utf-8"?> <jack:Blackjack xmlns:jack="http://www.blackjack.com">
The XML in Listing Two shows the proper placement of the namespace jack added to the XML from Listing One. The code in Listing Three incorporates the namespace in the LINQ-to-XML to obtain the net amount won (or lost) from the XML file in Listing One. The second half of the listing uses the XPathSelectElement method and an XPath query to obtain the same value.
<?xml version="1.0" encoding="utf-8"?> <jack:Blackjack xmlns:jack="http://www.blackjack.com"> <jack:Player Name="Player 1"> <jack:Statistics> <jack:AverageAmountLost>-28.125</jack:AverageAmountLost> <jack:AverageAmountWon>30.681818181818183</jack:AverageAmountWon> <jack:Blackjacks>1</jack:Blackjacks> <jack:Losses>8</jack:Losses>44 <jack:NetAverageWinLoss>5.9210526315789478</jack:NetAverageWinLoss> <jack:NetWinLoss>112.5</jack:NetWinLoss> <jack:PercentageOfBlackJacks>0.041666666666666664</jack: PercentageOfBlackJacks> <jack:PercentageOfLosses>33.333333333333329</jack:PercentageOfLosses> <jack:PercentageOfPushes>16.666666666666664</jack:PercentageOfPushes> <jack:PercentageOfWins>45.833333333333329</jack:PercentageOfWins> <jack:Pushes>4</jack:Pushes> <jack:Surrenders>1</jack:Surrenders> <jack:TotalAmountLost>-225</jack:TotalAmountLost> <jack:TotalAmountWon>337.5</jack:TotalAmountWon> <jack:Wins>11</jack:Wins> </jack:Statistics> </jack:Player> </jack:Blackjack>
using System.Xml; using System.Xml.Linq; using System.Xml.XPath; private static void UseNamespace() { const string filename = "..\\..\\CurrentStatsWithNamespace.xml"; XDocument doc = XDocument.Load(filename); XNamespace jack = "http://www.blackjack.com"; XElement winLoss1 = doc.Element(jack + "Blackjack") .Element(jack + "Player").Element ( jack + "Statistics").Element(jack + "NetWinLoss"); Console.WriteLine(winLoss1); Console.ReadLine(); XmlReader reader = XmlReader.Create(filename); XElement root = XElement.Load(reader); XmlNameTable table = reader.NameTable; XmlNamespaceManager manager = new XmlNamespaceManager(table); manager.AddNamespace("jack", "http://www.blackjack.com"); XElement winLoss2 = doc.XPathSelectElement( "./jack:Blackjack/jack:Player/jack:Statistics/jack:NetWinLoss", manager); Console.WriteLine(winLoss2); Console.ReadLine(); }
In the example, an XmlReader was created from the XML file. The root XElement was obtained from the reader, followed by the Nametable. The Nametable is an instance of the System.Xml.Nametable class, and it contains the atomized names of the elements and attributes of the XML document. If a name appears multiple times in an XML document, it is stored only once in a Nametable, as a Common Language Runtime (CLR) object. Such storage permits object comparisons on these elements and attributes rather than a much more expensive string comparison. (This is managed for you.)
Next, the table is used to create an XmlNamespaceManager and the desired XML namespace string is added to the manager. Finally, the XmlNamespaceManager is passed as an argument to the XPathSelectElement method. The XPath query is "./jack:Blackjack/jack:Player/jack:Statistics/jack:NetWinLoss". The subpath "jack:" demonstrates how to incorporate the namespace in the XPath query.
Our examples use the XPath support provided by LINQ-to-XML in the System.Xml.Linq namespace. XPath support is provided in System.Xml.XPath too, and you would use different classes and behaviors if you were to use that approach. As an exercise, if you are interested, you can experiment by implementing the equivalent behaviors using the capabilities of the XPath namespace.