47

How do I get a NameTable from an XDocument?

It doesn't seem to have the NameTable property that XmlDocument has.

EDIT: Judging by the lack of an answer I'm guessing that I may be missing the point.

I am doing XPath queries against an XDocument like this...

document.XPathSelectElements("//xx:Name", namespaceManager);

It works fine but I have to manually add the namespaces I want to use to the XmlNamespaceManager rather than retrieving the existing nametable from the XDocument like you would with an XmlDocument.

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Simon Keep
  • 9,886
  • 9
  • 63
  • 78
  • please take a look at the given link for a possible answer.... http://stackoverflow.com/questions/879728/can-i-use-predefined-namespaces-when-loading-an-xdocument – Sandeep Datta May 14 '10 at 08:26

4 Answers4

35

You need to shove the XML through an XmlReader and use the XmlReader's NameTable property.

If you already have Xml you are loading into an XDocument then make sure you use an XmlReader to load the XDocument:-

XmlReader reader = new XmlTextReader(someStream);
XDocument doc = XDocument.Load(reader);
XmlNameTable table = reader.NameTable;

If you are building Xml from scratch with XDocument you will need to call XDocument's CreateReader method then have something consume the reader.

Once the reader has be used (say, by loading another XDocument, or better: some do-nothing sink which just causes the reader to run through the XDocument's contents) you can retrieve the NameTable.

General Grievance
  • 4,555
  • 31
  • 31
  • 45
AnthonyWJones
  • 187,081
  • 35
  • 232
  • 306
32

I did it like this:

//Get the data into the XDoc
XDocument doc = XDocument.Parse(data);
//Grab the reader
var reader = doc.CreateReader();
//Set the root
var root = doc.Root;
//Use the reader NameTable
var namespaceManager = new XmlNamespaceManager(reader.NameTable);
//Add the GeoRSS NS
namespaceManager.AddNamespace("georss", "http://www.georss.org/georss");  
//Do something with it
Debug.WriteLine(root.XPathSelectElement("//georss:point", namespaceManager).Value);  
General Grievance
  • 4,555
  • 31
  • 31
  • 45
  • if you had only the xml text or the XDocument that's the only way, but if you had the XmlReader the previous solution is more efficient. – dmihailescu Mar 10 '15 at 20:59
7

I have to manually add the namespaces I want to use to the XmlNamespaceManager rather than retrieving the existing nametable from the XDocument like you would with an XmlDocument.

XDocument project = XDocument.Load(path);
//Or: XDocument project = XDocument.Parse(xml);
var nsMgr = new XmlNamespaceManager(new NameTable());
//Or: var nsMgr = new XmlNamespaceManager(doc.CreateReader().NameTable);
nsMgr.AddNamespace("msproj", "http://schemas.microsoft.com/developer/msbuild/2003");
var itemGroups = project.XPathSelectElements(@"msproj:Project/msproj:ItemGroup", nsMgr).ToList();
Alex
  • 423
  • 4
  • 7
  • i.e. FWIW, just to clarify, the `XmlNameSpaceManager` seemingly can use *any* `NameTable` (even a new, empty one) when using the `System.Xml.Xpath` extensions - it doesn't have to be related to the `XDocument`, Another example of this working [here](https://stackoverflow.com/a/50502943/314291) – StuartLC May 24 '18 at 07:12
3

It can also be done by XPathNavigator. Can be useful when you know neither Xml file Encoding nor namespace prefixes.

XDocument xdoc = XDocument.Load(sourceFileName);
XPathNavigator navi = xdoc.Root.CreateNavigator();
XmlNamespaceManager xmlNSM = new XmlNamespaceManager(navi.NameTable);
//Get all the namespaces from navigator
IDictionary<string, string> dict = navi.GetNamespacesInScope(XmlNamespaceScope.All);
//Copy them into Manager
foreach (KeyValuePair<string, string> pair in dict)
{
    xmlNSM.AddNamespace(pair.Key, pair.Value);
}