2012-01-22 30 views
11

En relación con this previous question Estoy tratando de crear un archivo por lotes que como parte debe eliminar y agregar una referencia a un archivo XML * .csproj. He mirado this, this, this y this pregunta previa pero como un powershell n00b soy incapaz de hacerlo funcionar (hasta ahora).¿Cómo uso Powershell para agregar/eliminar referencias a un csproj?

¿Alguien me puede ayudar con lo siguiente? Quiero eliminar dos referencias específicas en un archivo VS2010 csproj (XML) y agregar una nueva referencia.

me abrió la csproj y la referencia se puede encontrar en la siguiente ubicación

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

    <!--   ...   --> 
    <!-- Omitted for brevity --> 
    <!--   ...   --> 

    <ItemGroup Condition="'$(BuildingInsideVisualStudio)' == 'true'"> 
    <AvailableItemName Include="Effect" /> 
    </ItemGroup> 
    <ItemGroup> 
    <ProjectReference Include="..\SomeDirectory\SomeProjectFile.csproj"> 
     <Project>{AAB784E4-F8C6-4324-ABC0-6E9E0F73E575}</Project> 
     <Name>SomeProject</Name> 
    </ProjectReference> 
    <ProjectReference Include="..\AnotherDirectory\AnotherProjectFile.csproj"> 
     <Project>{B0AA6A94-6784-4221-81F0-244A68C374C0}</Project> 
     <Name>AnotherProject</Name> 
    </ProjectReference> 
    </ItemGroup> 

    <!--   ...   --> 
    <!-- Omitted for brevity --> 
    <!--   ...   --> 

</Project> 

Básicamente quiero:

  • eliminar estas dos referencias
  • insertar una nueva referencia a un pre -Compiled DLL especificado por la ruta relativa
  • O Agregue una ubicación de referencia de conjunto al proyecto especificado por la ruta relativa

Como un ejemplo muy simple, he intentado el siguiente script de PowerShell para eliminar todos los nodos ProjectReference. Paso el camino a csproj como argumento. Me aparece el error Cannot validate the argument 'XML'. The Argument is null or empty. Puedo confirmar que es cargando el csproj y guardándolo in situ sin modificar para que la ruta sea correcta.

param($path) 
$MsbNS = @{msb = 'http://schemas.microsoft.com/developer/msbuild/2003'} 

function RemoveElement([xml]$Project, [string]$XPath, [switch]$SingleNode) 
{ 
    $xml | Select-Xml -XPath $XPath | ForEach-Object{$_.Node.ParentNode.RemoveAll()} 
} 

$proj = [xml](Get-Content $path) 
[System.Console]::WriteLine("Loaded project {0} into {1}", $path, $proj) 

RemoveElement $proj "//ProjectReference" -SingleNode 

    # Also tried 
    # RemoveElement $proj "/Project/ItemGroup/ProjectReference[@Include=`'..\SomeDirectory\SomeProjectFile.csproj`']" -SingleNode 
    # but complains cannot find XPath 

$proj.Save($path) 

¿Qué estoy haciendo mal? Cualquier comentario/sugerencia bienvenida :)

Respuesta

23

Creo que el problema es que su archivo XML tiene un espacio de nombre predeterminado xmlns="http://schemas.microsoft.com/developer/msbuild/2003". Esto causa problemas con XPath. Entonces XPath //ProjectReference devolverá 0 nodos. Hay dos formas de solucionar esto:

  1. Use un administrador de espacio de nombres.
  2. Utilice el espacio de nombres agnóstico XPath.

Aquí es cómo se puede utilizar un gestor de espacio de nombres:

$nsmgr = New-Object System.Xml.XmlNamespaceManager -ArgumentList $proj.NameTable 
$nsmgr.AddNamespace('a','http://schemas.microsoft.com/developer/msbuild/2003') 
$nodes = $proj.SelectNodes('//a:ProjectReference', $nsmgr) 

O:

Select-Xml '//a:ProjectReference' -Namespace $nsmgr 

He aquí cómo hacerlo utilizando espacio de nombres XPath agnóstico:

$nodes = $proj.SelectNodes('//*[local-name()="ProjectReference"]') 

O :

$nodes = Select-Xml '//*[local-name()="ProjectReference"]' 

El segundo enfoque puede ser peligroso porque si hubiera más de un espacio de nombre podría seleccionar los nodos incorrectos, pero no en su caso.

+0

Wow, muy ¡servicial! Déjame probar esto. Gracias –

+0

primer intento, llamé 'proj.NameTable 'y' nsmgr.AddNamespace' y obtuve 'System.Xml.Nametable' no contiene un método llamado AddNamespace' –

+0

duh' [System.Xml.XmlNamespaceManager] $ nsmgr = $ proj.NameTable' funciona. Ok trabajando a través de esto para eliminar los nodos. Parece estar seleccionando nodos sin error –

19

Para las posteridades, daré los scripts completos de powershell para agregar y eliminar referencias a archivos csproj.Por favor, vote la respuesta de Andy Arismedi si le resulta útil, ya que me ayudó a encontrarlo. No dude en darme un 1 también mientras estás en ello ;-)

AddReference.ps1

# Calling convension: 
#   AddReference.PS1 "Mycsproj.csproj",  
#        "MyNewDllToReference.dll",  
#     "MyNewDllToReference" 
param([String]$path, [String]$dllRef, [String]$refName) 

$proj = [xml](Get-Content $path) 
[System.Console]::WriteLine("") 
[System.Console]::WriteLine("AddReference {0} on {1}", $refName, $path) 

# Create the following hierarchy 
#  <Reference Include='{0}'> 
#     <HintPath>{1}</HintPath> 
#  </Reference> 
# where (0) is $refName and {1} is $dllRef 

$xmlns = "http://schemas.microsoft.com/developer/msbuild/2003" 
$itemGroup = $proj.CreateElement("ItemGroup", $xmlns); 
$proj.Project.AppendChild($itemGroup); 

$referenceNode = $proj.CreateElement("Reference", $xmlns); 
$referenceNode.SetAttribute("Include", $refName); 
$itemGroup.AppendChild($referenceNode) 

$hintPath = $proj.CreateElement("HintPath", $xmlns); 
$hintPath.InnerXml = $dllRef 
$referenceNode.AppendChild($hintPath) 

$proj.Save($path) 

RemoveReference.ps1

# Calling Convention 
# RemoveReference.ps1 "MyCsProj.csproj" 
# "..\SomeDirectory\SomeProjectReferenceToRemove.dll" 
param($path, $Reference) 

$XPath = [string]::Format("//a:ProjectReference[@Include='{0}']", $Reference) 

[System.Console]::WriteLine(""); 
[System.Console]::WriteLine("XPATH IS {0}", $XPath) 
[System.Console]::WriteLine(""); 

$proj = [xml](Get-Content $path) 
[System.Console]::WriteLine("Loaded project {0} into {1}", $path, $proj) 

[System.Xml.XmlNamespaceManager] $nsmgr = $proj.NameTable 
$nsmgr.AddNamespace('a','http://schemas.microsoft.com/developer/msbuild/2003') 
$node = $proj.SelectSingleNode($XPath, $nsmgr) 

if (!$node) 
{ 
    [System.Console]::WriteLine(""); 
    [System.Console]::WriteLine("Cannot find node with XPath {0}", $XPath) 
    [System.Console]::WriteLine(""); 
    exit 
} 

[System.Console]::WriteLine("Removing node {0}", $node) 
$node.ParentNode.RemoveChild($node); 

$proj.Save($path) 
+4

Solo un FYI. En lugar de '[system.console] :: WriteLine', puede usar el cmdlet' Write-Host', p. 'Write-Host (" Esto es {0} tipeando "-f" menos ")'. '-f' es para el formateo de cadenas :-) –

Cuestiones relacionadas