これを説明するのは難しいでしょうが、最善を尽くします。不明な点がある場合は、説明/追加のためにコメントを追加してください。
背景情報:
- msbuild を実行する NANT (ビルド プロセス) バージョン 0.85.2478.0
- CruiseControl.NET
- Windows Server 2008 R2 64 ビット
- .NET フレームワーク 3.5
Web アプリケーションの web.config でいくつかの設定を更新/変更しようとしています。NANT コードを使用して、CruiseControl.NET 経由で実行されるビルド プロセスを実行します。XslCompiledTransform を介して構成ファイルを更新し、スタイルシートと設定ファイルを使用しています。
「UpdateConfig.xslt」ファイルは次のようになります。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt">
<!-- Set the file output mode -->
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
<!-- Get the parameters from the calling application -->
<xsl:param name="defaultSettings" select="'C:\BuildServer\Configuration\ConfigFiles\Defaults.xml'" />
<xsl:param name="buildTypeSettings" select="'NoFile'" />
<xsl:param name="environmentSettings" select="'NoFile'" />
<xsl:param name="projectSettings" select="'NoFile'" />
<xsl:param name="mode" select="''"/>
<!-- Load the various ConfigFileSettings XML files. -->
<xsl:include href="GetSettings.xslt" />
<xsl:variable name="fileset">
<xsl:if test="$defaultSettings != 'NoFile'">
<xsl:element name="File"><xsl:value-of select="$defaultSettings" /></xsl:element>
</xsl:if>
<xsl:if test="$buildTypeSettings != 'NoFile'">
<xsl:element name="File"><xsl:value-of select="$buildTypeSettings" /></xsl:element>
</xsl:if>
<xsl:if test="$environmentSettings != 'NoFile'">
<xsl:element name="File"><xsl:value-of select="$environmentSettings" /></xsl:element>
</xsl:if>
<xsl:if test="$projectSettings != 'NoFile'">
<xsl:element name="File"><xsl:value-of select="$projectSettings" /></xsl:element>
</xsl:if>
</xsl:variable>
<xsl:variable name="Settings">
<xsl:call-template name="loadSettings">
<xsl:with-param name="fileset" select="$fileset" />
</xsl:call-template>
</xsl:variable>
<!-- Define the root node template to distinguish output types. -->
<xsl:template match="/">
<xsl:choose>
<xsl:when test="$mode = 'display'">
<xsl:call-template name="display" />
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- Define the default copy template. -->
<xsl:template match="*|node()|comment()|processing-instruction()" priority="-100">
<xsl:copy><xsl:apply-templates select="@*|node()" /></xsl:copy>
</xsl:template>
<!-- Skip certain comments. -->
<xsl:template match="comment()[contains(., '=tuc0') and contains(., '<publisher')]" />
<xsl:template match="comment()[contains(., 'add key="')]" priority="10">
<xsl:variable name="key" select="substring-before(substring-after(., 'add key="'), '"')" />
<xsl:if test="count(//add[@key=$key]) = 0"><xsl:copy /></xsl:if>
</xsl:template>
<!-- Look up attribute settings in the $Settings block for all attributes. -->
<xsl:template match="@*">
<xsl:choose>
<xsl:when test="name() = '@key'"><xsl:copy /></xsl:when>
<xsl:otherwise>
<!-- First, build a full xpath to this key as it should appear in settings. -->
<xsl:variable name="setting">
<xsl:call-template name="getSetting">
<xsl:with-param name="node" select="." />
</xsl:call-template>
</xsl:variable>
<!-- Next, get the value from the config file if it's there. -->
<xsl:variable name="value">
<xsl:choose>
<xsl:when test="count(msxsl:node-set($Settings)//setting[@xpath=$setting]) = 1">
<xsl:value-of select="msxsl:node-set($Settings)//setting[@xpath=$setting]/@value" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="." />
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<!-- Finally, return the attribute with its new value -->
<xsl:attribute name="{name()}"><xsl:value-of select="$value" /></xsl:attribute>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- Handle SQL Connection Strings -->
<xsl:template match="@*[(contains(translate(., 'ACDEGILNORSTU ', 'acdegilnorstu'), 'initialcatalog=')
or contains(translate(., 'ABDEST ', 'abdest'), 'database='))
and not(contains(translate(., 'PROVIDE ', 'provide'), 'provider='))]"
priority="1">
<!-- Normalize the connection string -->
<xsl:variable name="lcString" select="translate(., 'ABCDEGILNORSTU ', 'abcdegilnorstu')" />
<!-- Get the database from the string -->
<xsl:variable name="dbname">
<xsl:choose>
<xsl:when test="contains($lcString, 'initialcatalog=')">
<xsl:value-of select="substring-before(substring-after($lcString, 'initialcatalog='), ';')" />
</xsl:when>
<xsl:when test="contains($lcString, 'database=')">
<xsl:value-of select="substring-before(substring-after($lcString, 'database='), ';')" />
</xsl:when>
</xsl:choose>
</xsl:variable>
<xsl:variable name="SqlDB" select="concat('Initial Catalog=', $dbname, ';')" />
<!-- Get SQL Settings from $Settings. -->
<xsl:variable name="SqlAuth">
<xsl:choose>
<xsl:when test="translate(msxsl:node-set($Settings)//SqlAuth, 'TRUE', 'true') = 'true'">
<xsl:text>Trusted_Connection=YES;</xsl:text>
</xsl:when>
<xsl:otherwise><xsl:text>Trusted_Connection=NO;</xsl:text></xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="SqlServer">
<xsl:choose>
<xsl:when test="count(msxsl:node-set($Settings)//SqlServer) > 0">
<xsl:value-of select="concat('Data Source=', msxsl:node-set($Settings)//SqlServer, ';')" />
</xsl:when>
<xsl:otherwise>.</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="SqlUser">
<xsl:if test="$SqlAuth = 'Trusted_Connection=NO;' and string-length(msxsl:node-set($Settings)//SqlUser) > 0">
<xsl:value-of select="concat('user id=', msxsl:node-set($Settings)//SqlUser, ';')" />
</xsl:if>
</xsl:variable>
<xsl:variable name="SqlPass">
<xsl:if test="$SqlAuth = 'Trusted_Connection=NO;' and string-length(msxsl:node-set($Settings)//SqlPass) > 0">
<xsl:value-of select="concat('password=', msxsl:node-set($Settings)//SqlPass, ';')" />
</xsl:if>
</xsl:variable>
<xsl:variable name="SqlApp">
<xsl:if test="string-length(msxsl:node-set($Settings)//SqlApp) > 0">
<xsl:value-of select="concat('APP=', msxsl:node-set($Settings)//SqlApp, ';')" />
</xsl:if>
</xsl:variable>
<xsl:attribute name="{name()}"><xsl:value-of select="concat($SqlServer,$SqlDB,$SqlAuth,$SqlUser,$SqlPass,$SqlApp)" /></xsl:attribute>
</xsl:template>
<xsl:template name="getSetting">
<xsl:param name="node" />
<xsl:param name="xpath" select="name($node)" />
<xsl:param name="r" select="'1'" />
<xsl:for-each select="$node"> <!-- Sets the node as current context -->
<!-- Handle any special formatting for identifying settings -->
<xsl:variable name="setting">
<xsl:choose>
<xsl:when test="name(..) = 'FTPLocation' and ../@name">
<xsl:value-of select='concat("[@name='", ../@name, "']/@", $xpath)' />
</xsl:when>
<xsl:when test="name() = 'value' and name(..) = 'add' and ../@key">
<xsl:value-of select='concat("[@key='", ../@key, "']/@", $xpath)' />
</xsl:when>
<xsl:when test="not(self::*)">
<xsl:value-of select="concat('/', '@', $xpath)" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat('/', $xpath)" />
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:choose>
<xsl:when test="name(..) = ''">
<xsl:value-of select="$setting" />
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="getSetting">
<xsl:with-param name="node" select=".." />
<xsl:with-param name="xpath" select="concat(name(..), $setting)" />
<xsl:with-param name="r" select="$r + 1" />
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
以下は、機能する値と機能しない値を含む設定ファイルの一部です。
<setting xpath="/configuration/General/Settings/add[@key='enableAddrValidationService']/@value" value="true" create="false" dynamic="false" />
<setting xpath="/configuration/General/Settings/add[@key='AddrValidationUrl']/@value" value="bogus" create="false" dynamic="false" />
<setting xpath="/configuration/system.serviceModel/client/endpoint[@name='ValidationServiceSoap']/@address" value="bogus" create="false" dynamic="false" />
<setting xpath="/configuration/applicationSettings/ARTS.Properties.Settings/setting[@name='addrValidationUser']/value" value="bogus" create="false" dynamic="false" />
問題: Web アプリケーションのビルドを開始すると、必要な / 指定したすべての構成セクションが更新されません。
XmlSpy、Notepad++、および XmlQuire を使用してすべての xpath 式を検証したので、それらが正しいことは 100% わかっています。
何が間違っているかについての私の唯一の考えは、それがスタイルシート (UpdateConfig.xslt) にあるということですが、このビルド プロセスは私が書いたものではなく、読むのに苦労しています。
何が問題なのか、またはプロセスをより適切にデバッグする方法について誰かが考えている場合は、ぜひ聞いてください。
ああ、更新されないセクションは次の xpath です。
<setting xpath="/configuration/system.serviceModel/client/endpoint[@name='ValidationServiceSoap']/@address" value="bogus" create="false" dynamic="false" />