XmlDocument.SelectSingleNode and xmlNamespace issu

2019-01-01 13:23发布

问题:

I\'m loading a string to an XML document that contains the following structure :

<?xml version=\"1.0\" encoding=\"utf-8\"?>
<Project ToolsVersion=\"4.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">                  
  <ItemGroup>
    <Compile Include=\"clsWorker.cs\" />        
  </ItemGroup>      
</Project>

then im loading all into xmldocument :

XmlDocument xmldoc = new XmlDocument();
xmldoc.LoadXml(Xml);

then the following problem occurs :

XmlNode Node = xmldoc.SelectSingleNode(\"//Compile\"); // return null

when i remove the xmlns attribute from the root element(Project) its working fine, how can i improve my SelectSingleNode to return the relevant element ?

回答1:

You should use an XmlNamespaceManager in your call to SelectSingleNode():

XmlNamespaceManager ns = new XmlNamespaceManager(xmldoc.NameTable);
ns.AddNamespace(\"msbld\", \"http://schemas.microsoft.com/developer/msbuild/2003\");
XmlNode node = xmldoc.SelectSingleNode(\"//msbld:Compile\", ns);


回答2:

Taken right from the documentation of SelectSingleNode() on the MSDN:

Note
If the XPath expression does not include a prefix, it is assumed that the namespace URI is the empty namespace. If your XML includes a default namespace, you must still add a prefix and namespace URI to the XmlNamespaceManager; otherwise, you will not get a node selected. For more information, see Select Nodes Using XPath Navigation.

And the immediately following sample code is

XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace(\"ab\", \"http://www.lucernepublishing.com\");
XmlNode book = doc.SelectSingleNode(\"//ab:book\", nsmgr);

It\'s not as if this would be \"hidden knowledge\". ;-)



回答3:

Since the \'ItemGroup\' may have multiple \'Compile\' children, and you specifically want the \'Compile\' children of \'Project/ItemGroup\', the following will return all of the desired \'Compile\' children and no others:

XmlDocument projectDoc = new XmlDocument();
projectDoc.Load(projectDocPath);
XmlNamespaceManager ns = new XmlNamespaceManager(projectDoc.NameTable);
ns.AddNamespace(\"msbld\", \"http://schemas.microsoft.com/developer/msbuild/2003\");
XmlNodeList xnList = projectDoc.SelectNodes(@\"/msbld:Project/msbld:ItemGroup/msbld:Compile\", ns);

Note that the \'msbld:\' namespace specification needs to precede each node level.



回答4:

This way you don\'t need to specify namespace:

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(\"your xml\");
XmlNode node = xmlDoc.SelectSingleNode(\"/*[local-name() = \'Compile\']\");
XmlNode nodeToImport = xmlDoc2.ImportNode(node, true);
xmlDoc2.AppendChild(nodeToImport);