web-dev-qa-db-fra.com

Problème avec XmlDocument.SelectSingleNode et xmlNamespace

Je charge une chaîne dans un document XML qui contient la structure suivante:

<?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>

puis je charge tout dans xmldocument:

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

alors le problème suivant se produit:

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

lorsque je supprime l'attribut xmlns de l'élément racine (Project), cela fonctionne correctement, comment puis-je améliorer mon SelectSingleNode pour renvoyer l'élément pertinent?

43
Shlomi Komemi

Vous devez utiliser un XmlNamespaceManager dans votre appel à SelectSingleNode () :

XmlNamespaceManager ns = new XmlNamespaceManager(xmldoc.NameTable);
ns.AddNamespace("msbld", "http://schemas.Microsoft.com/developer/msbuild/2003");
XmlNode node = xmldoc.SelectSingleNode("//msbld:Compile", ns);
81
Frédéric Hamidi

Tiré directement de la documentation de SelectSingleNode() sur le MSDN :

Remarque
Si l'expression XPath n'inclut pas de préfixe, il est supposé que l'URI de l'espace de noms est l'espace de noms vide. Si votre XML comprend un espace de noms par défaut, vous devez toujours ajouter un préfixe et un URI d'espace de noms au XmlNamespaceManager; sinon, aucun nœud ne sera sélectionné. Pour plus d'informations, consultez Sélectionner les nœuds à l'aide de la navigation XPath .

Et l'exemple de code suivant est

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

C'estpascommesiceciserait - être " cachéconnaissance ". ;-)

18
Tomalak

Étant donné que 'ItemGroup' peut avoir plusieurs enfants 'Compile', et que vous voulez spécifiquement les enfants 'Compile' de 'Project/ItemGroup', ce qui suit renverra tous les enfants 'Compile' souhaités et aucun autre:

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);

Notez que la spécification d'espace de noms 'msbld:' doit précéder chaque niveau de nœud.

3
user3902302

De cette façon, vous n'avez pas besoin de spécifier d'espace de noms:

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