2012-01-22 44 views
11

關於this previous question我想創建一個批處理文件,作爲部分必須刪除並添加一個對XML * .csproj文件的引用。我已經看過this,this,thisthis上一個問題,但作爲PowerShell的n00b我無法得到它的工作(到目前爲止)。如何使用Powershell添加/刪除對csproj的引用?

任何人都可以幫助我以下嗎?我想在VS2010 csproj文件(XML)中刪除兩個特定的引用並添加一個新的引用。

我打開的csproj和參考可在以下位置找到

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

基本上我想:

  • 刪除這兩個引用
  • 插入一個新的參照預 - 由相對路徑指定的編譯DLL
  • 或將組件參考位置添加到由相對路徑指定的項目

作爲一個非常簡單的例子,我嘗試了下面的PowerShell腳本來刪除所有的ProjectReference節點。我將路徑傳遞給csproj作爲參數。我收到錯誤Cannot validate the argument 'XML'. The Argument is null or empty。我可以確認它加載csproj並將其保存在原地而未修改,因此路徑是正確的。

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) 

我在做什麼錯?任何意見/建議歡迎:)

回答

23

我認爲問題是你的XML文件有一個默認名稱空間xmlns="http://schemas.microsoft.com/developer/msbuild/2003"。這會導致XPath出現問題。所以你XPath //ProjectReference將返回0個節點。有兩種方法可以解決這個問題:

  1. 使用命名空間管理器。
  2. 使用命名空間不可知的XPath。

這裏的是你如何可以使用一個命名空間管理:

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

或者:

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

這裏是如何使用的命名空間不可知XPath來做到這一點:

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

或者:

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

第二種方法可能很危險,因爲如果有多個名稱空間,它可能會選擇錯誤的節點,但不是您的情況。

+0

哇塞,太有幫助!讓我試試這個。謝謝 –

+0

第一次嘗試,我調用了'proj.NameTable'和'nsmgr.AddNamespace',並得到'System.Xml.Nametable不包含名爲AddNamespace的方法' –

+0

duh'[System.Xml.XmlNamespaceManager] $ nsmgr = $ proj.NameTable'的作品。確定通過這個去除節點。似乎選擇節點沒有錯誤 –

19

爲了後代的緣故,我會給完整的powershell腳本添加和刪除對csproj文件的引用。如果你發現這個有用的,請幫助Andy Arismedi的回答,因爲他幫助我找到它。隨時給我一個+1也,而你在它;-)

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

只是一個供參考。而不是'[system.console] :: WriteLine',你可以使用'Write-Host' cmdlet,例如'Write-Host(「這是{0}輸入」-f「less」)''。 '-f'用於字符串格式:-) –

相關問題