2010-09-19 17 views
10

Mi mancano sicuramente alcuni dettagli importanti qui. Non riesco proprio a far funzionare XPath di .NET con i file di progetto di Visual Studio.XPath e * .csproj

Facciamo caricare un documento XML:

var doc = new XmlDocument(); 
doc.Load("blah/blah.csproj"); 

Ora eseguire la mia domanda:

var nodes = doc.SelectNodes("//ItemGroup"); 
Console.WriteLine(nodes.Count); // whoops, zero 

Naturalmente, ci sono nodi denominati ItemGroup nel file. Inoltre, questa query funziona:

var nodes = doc.SelectNodes("//*/@Include"); 
Console.WriteLine(nodes.Count); // found some 

Con altri documenti, XPath funziona perfettamente. Sono assolutamente perplesso su questo. Qualcuno potrebbe spiegarmi cosa sta succedendo?

+0

Cosa dire di 'var nodes = doc.SelectNodes (" // */ItemGroup ");' Ora sono in Mac OS X quindi non posso verificarlo. – Strelok

risposta

14

probabilmente, è necessario aggiungere un riferimento allo spazio dei nomi http://schemas.microsoft.com/developer/msbuild/2003.

ho avuto un problema simile, ho scritto su di esso here. Fare qualcosa di simile:

XmlDocument xdDoc = new XmlDocument(); 
xdDoc.Load("blah/blah.csproj"); 

XmlNamespaceManager xnManager = 
new XmlNamespaceManager(xdDoc.NameTable); 
xnManager.AddNamespace("tu", 
"http://schemas.microsoft.com/developer/msbuild/2003"); 

XmlNode xnRoot = xdDoc.DocumentElement; 
XmlNodeList xnlPages = xnRoot.SelectNodes("//tu:ItemGroup", xnManager); 
+0

che può non ** ** lavoro possibilmente, dal momento che non avete utilizzato * * gli alias da nessuna parte ... –

+0

Questo è sbagliato ... –

+0

sì, ho perso l'alias nel XPath –

9

Controllare lo spazio dei nomi radice; dovrai includere un gestore di namespace xml e utilizzare query come "// x: ItemGroup", dove "x" è l'alias designato per lo spazio dei nomi di root. E passare il gestore nella query. Per esempio:

 XmlDocument doc = new XmlDocument(); 
     doc.Load("my.csproj"); 

     XmlNamespaceManager mgr = new XmlNamespaceManager(doc.NameTable); 
     mgr.AddNamespace("foo", doc.DocumentElement.NamespaceURI); 
     XmlNode firstCompile = doc.SelectSingleNode("//foo:Compile", mgr); 
+0

L'aggiunta di uno spazio dei nomi ha funzionato. Peccato che non si possano accettare due risposte per una domanda :-) – catbert

+1

@catbert: è possibile invertire la risposta attualmente accettata (che è errata) e accettare la risposta corretta (la risposta di @ Marc-Gravell). Non solo tu puoi, ma dovresti farlo perché altrimenti alcune persone penseranno che la risposta errata/accettata sia corretta. –

+0

+1 Questo è rigoroso. –

5

Ho pubblicato una versione LINQ/Xml sopra a:

http://granadacoder.wordpress.com/2012/10/11/how-to-find-references-in-a-c-project-file-csproj-using-linq-xml/

Ma ecco l'essenza di esso. Potrebbe non essere perfetto al 100% ... ma mostra l'idea.

sto postando il codice qui, dal momento che ho trovato questo (post originale) durante la ricerca di una risposta. Poi mi sono stancato di cercare e ho scritto il mio.

  string fileName = @"C:\MyFolder\MyProjectFile.csproj"; 

      XDocument xDoc = XDocument.Load(fileName); 

      XNamespace ns = XNamespace.Get("http://schemas.microsoft.com/developer/msbuild/2003"); 

      //References "By DLL (file)" 
      var list1 = from list in xDoc.Descendants(ns + "ItemGroup") 
         from item in list.Elements(ns + "Reference") 
         /* where item.Element(ns + "HintPath") != null */ 
        select new 
         { 
          CsProjFileName = fileName, 
          ReferenceInclude = item.Attribute("Include").Value, 
          RefType = (item.Element(ns + "HintPath") == null) ? "CompiledDLLInGac" : "CompiledDLL", 
          HintPath = (item.Element(ns + "HintPath") == null) ? string.Empty : item.Element(ns + "HintPath").Value 
         }; 


      foreach (var v in list1) 
      { 
       Console.WriteLine(v.ToString()); 
      } 


      //References "By Project" 
      var list2 = from list in xDoc.Descendants(ns + "ItemGroup") 
         from item in list.Elements(ns + "ProjectReference") 
         where 
         item.Element(ns + "Project") != null 
         select new 
         { 
          CsProjFileName = fileName, 
          ReferenceInclude = item.Attribute("Include").Value, 
          RefType = "ProjectReference", 
          ProjectGuid = item.Element(ns + "Project").Value 
         }; 


      foreach (var v in list2) 
      { 
       Console.WriteLine(v.ToString()); 
      } 
+0

non al 100% perfetto? Mi andava bene, ma quali sarebbero le insidie ​​se non ti dispiace che me lo chieda dopo 2 anni – mechanicum

+0

Non so cosa faccia con i riferimenti GAC, questo è l'unico sconosciuto, perché raramente faccio riferimenti GAC al di fuori del framework principale. Questo è tutto. Uso ancora la sceneggiatura quando ho bisogno di un "referto" di un povero uomo ... – granadaCoder