是否可以在 MSBuild 之外使用 Microsoft 的 XML 文档转换来准备 web.configs?我想使用 PowerShell 进行这些转换,而无需通过 MSBuild 引擎运行。如果 Microsoft 使用标准 XSLT,在 PowerShell 中将很容易做到。据我所知,我必须使用他们的 C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll 这需要构建引擎。谢谢
8 回答
我创建了一个小函数来在 PowerShell 中处理 Microsoft 的 XML 文档转换。
我将 Microsoft.Web.XmlTransform.dll 文件从 Visual Studio 构建文件夹复制到我的脚本路径,但如果您愿意,可以从源文件夹中引用它。
function XmlDocTransform($xml, $xdt)
{
if (!$xml -or !(Test-Path -path $xml -PathType Leaf)) {
throw "File not found. $xml";
}
if (!$xdt -or !(Test-Path -path $xdt -PathType Leaf)) {
throw "File not found. $xdt";
}
$scriptPath = (Get-Variable MyInvocation -Scope 1).Value.InvocationName | split-path -parent
Add-Type -LiteralPath "$scriptPath\Microsoft.Web.XmlTransform.dll"
$xmldoc = New-Object Microsoft.Web.XmlTransform.XmlTransformableDocument;
$xmldoc.PreserveWhitespace = $true
$xmldoc.Load($xml);
$transf = New-Object Microsoft.Web.XmlTransform.XmlTransformation($xdt);
if ($transf.Apply($xmldoc) -eq $false)
{
throw "Transformation failed."
}
$xmldoc.Save($xml);
}
使用 web.release.config 转换 web.config:
XmlDocTransform -xml "Web.config" -xdt "Web.Release.config"
或者,您可以使用 Sayed 的自引导 Xml 转换脚本,该脚本将为您获取 Microsoft.Xml.Xdt.dll:
转换的逻辑包含在 TransformXml 任务本身中。如果您想从代码中调用它,则必须使用带有模拟引擎的 MSBuild API 并执行它。如果你愿意,我有一些代码。
在您的情况下,既然您提到了 PowerShell,那么您最好的办法就是创建一个包装器 MSBuild 文件来调用 TransformXml 任务。我这样说是因为 PowerShell 配置为在 .NET 2.0 下运行,但 TransformXml 任务需要 .NET 4.0。为了从一个虚拟的 MSBuild 文件中调用它,您可以在http://sedodream.com/2010/04/26/ConfigTransformationsOutsideOfWebAppBuilds.aspx查看我的博客,但我还在下面的链接中粘贴了一个示例。
<Project ToolsVersion="4.0" DefaultTargets="Demo" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<UsingTask TaskName="TransformXml"
AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll"/>
<Target Name="Demo">
<TransformXml Source="app.config"
Transform="Transform.xml"
Destination="app.prod.config"/>
</Target>
</Project>
对于mono
,这应该可以工作(在 mono 6.4,macos,2019 上测试):
<Project DefaultTargets="TransformConfig" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<UsingTask TaskName="TransformXml"
AssemblyFile="$(MSBuildSDKsPath)/Microsoft.NET.Sdk.Publish/tools/net46/Microsoft.NET.Sdk.Publish.Tasks.dll"/>
<PropertyGroup>
<TransformSource>Web.config</TransformSource>
<Transformer>Web.Live.config</Transformer>
<Destination>Output.Web.config</Destination>
</PropertyGroup>
<Target Name="TransformConfig">
<Message Text="From TransformSource : $(TransformSource)" />
<Message Text="Using Transform : $(Transformer)" />
<Message Text="Output : $(Destination)" />
<Message Text="MSBuildSDKsPath=$(MSBuildSDKsPath)" Condition="'$(MSBuildSDKsPath)' != ''" />
<TransformXml Source="$(TransformSource)" Transform="$(Transformer)" Destination="$(Destination)"/>
</Target>
</Project>
您可以使用它运行msbuild
或提供参数
msbuild /p:TransformSource=... /p:Transformer=...
根据 Michel 的回答,我编写了一个 C# 函数来完成相同的任务。
当然,您可以使用 PowerShell 调用生成的 DLL,但我实际上是在寻找一个完全程序化的版本,所以在这里,以防其他人正在寻找类似的解决方案:
using Microsoft.Web.XmlTransform;
...
public static void TransformConfig(string configFileName, string transformFileName)
{
var document = new XmlTransformableDocument();
document.PreserveWhitespace = true;
document.Load(configFileName);
var transformation = new XmlTransformation(transformFileName);
if (!transformation.Apply(document))
{
throw new Exception("Transformation Failed");
}
document.Save(configFileName);
}
您只需要包含对以下内容的引用:
C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\Web\Microsoft.Web.XmlTransform.dll
Microsoft 已将 XDT 发布到 codeplex http://xdt.codeplex.com和作为 NuGet 包https://www.nuget.org/packages/Microsoft.Web.Xdt/。我还创建了一个带有 MSBuild 任务、TransformXml 和 .exe 的 NuGet 猪来调用它们https://www.nuget.org/packages/SlowCheetah.Xdt/1.1.6-beta。
对于 PowerShell,我创建了一个自引导脚本,您可以使用它https://gist.github.com/sayedihashimi/f1fdc4bfba74d398ec5b。
有关自引导脚本的更多信息,请访问http://sedodream.com/2014/07/22/StopCheckinginBinariesInsteadCreateSelfbootstrappingScripts.aspx。
我稍微更新了脚本以使其与最新版本的 powershell 一起工作并使其更容易一些。
function XmlDocTransform($xml, $xdt)
{
$scriptpath = $PSScriptRoot + "\"
$xmlpath = $scriptpath + $xml
$xdtpath = $scriptpath + $xdt
if (!($xmlpath) -or !(Test-Path -path ($xmlpath) -PathType Leaf)) {
throw "Base file not found. $xmlpath";
}
if (!($xdtpath) -or !(Test-Path -path ($xdtpath) -PathType Leaf)) {
throw "Transform file not found. $xdtpath";
}
Add-Type -LiteralPath "$PSScriptRoot\Microsoft.Web.XmlTransform.dll"
$xmldoc = New-Object Microsoft.Web.XmlTransform.XmlTransformableDocument;
$xmldoc.PreserveWhitespace = $true
$xmldoc.Load($xmlpath);
$transf = New-Object Microsoft.Web.XmlTransform.XmlTransformation($xdtpath);
if ($transf.Apply($xmldoc) -eq $false)
{
throw "Transformation failed."
}
$xmldoc.Save($xmlpath);
Write-Host "Transformation succeeded" -ForegroundColor Green
}
并调用函数使用
XmlDocTransform "App.config" "App.acc.config"
看看使用 MSDeploy,因为它具有 PowerShell 脚本 API,允许您转换和部署您的包。
您还可以查看XML-Document-Transform,如果您愿意,您可以编写自己的代码来执行转换。
这是一个执行类似操作的 codeplex 项目。XDT 转换工具
所以稍微扩展以递归工作
function XmlDocTransform($xml, $xdt)
{
if (!$xml -or !(Test-Path -path $xml -PathType Leaf)) {
throw "File not found. $xml";
}
if (!$xdt -or !(Test-Path -path $xdt -PathType Leaf)) {
throw "File not found. $xdt";
}
$scriptPath = (Get-Variable MyInvocation -Scope 1).Value.InvocationName | split-path -parent
Add-Type -LiteralPath "$scriptPath\Microsoft.Web.XmlTransform.dll"
$xmldoc = New-Object Microsoft.Web.XmlTransform.XmlTransformableDocument;
$xmldoc.PreserveWhitespace = $true
$xmldoc.Load($xml);
$transf = New-Object Microsoft.Web.XmlTransform.XmlTransformation($xdt);
if ($transf.Apply($xmldoc) -eq $false)
{
throw "Transformation failed."
}
$xmldoc.Save($xml);
}
function DoConfigTransform($webFolder, $environment)
{
$allConfigFiles = Get-ChildItem $webFolder -File -Filter *.config -Recurse
$transformFiles = $allConfigFiles | Where-Object {$_.Name -like ("*." + $environment + ".config")} | %{$_.fullname}
ForEach($item in $transformFiles)
{
$origFile = $item -replace("$environment.",'')
XmlDocTransform -xml $origFile -xdt $origFile$item
#Write-Output ("orig = " + $origFile + ", transform = " + $item)
}
cd C:\WebApplications\xxx\xxx\xxx\
.\PostDeploy.ps1
}
DoConfigTransform -webFolder "C:\WebApplications\xxx\xxx\xxx" -environment "xx-xxx-xx"
所以 DoConfigTransform 逻辑如下:
- 递归查找所有配置文件
- 查找我们所在环境的所有转换模板 #passed in 作为参数
- 对于每个转换文件,找到相应的配置
- 然后做变换
- 代码运行部署后脚本以删除所有不需要的转换文件。
我在原始发布之后很长时间才来到这篇文章,但它帮助解决了我的问题,所以我想我会把我的解决方案(基于上面的解决方案)放在这里,供任何与当前的 Visual Studio / msbuild 安装有相同问题的人使用。
目前在 VS 构建时转换是使用 SlowCheetah nuget pkg 完成的。如果你可以在你的项目中依赖这个包,你可以使用我在下面放置的脚本,它会根据安装的 cheetah 版本自动找到所需的程序集,并根据需要执行你的转换。
希望这可以帮助某人。
param(
[ValidateScript({$(Test-Path $_) -eq $true})]
[string] $NuGetRootPath,
[ValidateScript({$(Test-Path $_) -eq $true})]
[string] $BaseFile,
[ValidateScript({$(Test-Path $_) -eq $true})]
[string] $TransformFile,
[string] $TargetPath
)
"[INFO] Creating Custom XML Transform..." | Out-Default
"[INFO] ==> Source: $BaseFile" | Out-Default
"[INFO] ==> Transform: $TransformFile" | Out-Default
"[INFO] ==> Target: $TargetPath" | Out-Default
$cheetahDir = Join-Path $NuGetRootPath *SlowCheetah* | Resolve-Path | Select-Object -Last 1 -ExpandProperty Path
$xformDll = Join-Path $cheetahDir "tools\Microsoft.Web.XmlTransform.dll" | Resolve-Path | Select-Object -ExpandProperty Path
Add-Type -LiteralPath $xformDll
$xmldoc = New-Object Microsoft.Web.XmlTransform.XmlTransformableDocument;
$xmldoc.PreserveWhitespace = $true
$xmldoc.Load($BaseFile);
"[INFO] Running Transform..." | Out-Default
$transf = New-Object Microsoft.Web.XmlTransform.XmlTransformation($TransformFile);
if ($transf.Apply($xmldoc) -eq $false) {
throw "[ERROR] Transformation failed."
}
$xmldoc.Save($TargetPath);
"[INFO] Transformation Complete..." | Out-Default