用于解析WiX Processing-Instructions作为MsBuild属性的XPath表达式

时间:2013-04-26 13:49:33

标签: xpath msbuild wix

我有以下wix包括 VersionFile.wxi

<?xml version="1.0" encoding="utf-8"?>
<Include>
  <?define ProductVersionMajor = "1" ?>
  <?define ProductVersionMinor = "00" ?>

  <?define ProductName= "MyProduct" ?>

  <?define UpgradeCode = "myUpgradeCode" ?>
</Include>

现在我想得到ProductVersionMajor使用XmlPeek和XPath查询作为“1”或ProductName“MyProduct”(不带引号)。使用以下代码

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

  <Target Name="Test">

    <XmlPeek XmlInputPath="VersionFile.wxi"
             Query="//processing-instruction('define')[starts-with(., &quot;ProductVersionMajor =&quot;)]">
      <Output TaskParameter="Result" ItemName="Peeked" />
    </XmlPeek>

    <XmlPeek XmlInputPath="VersionFile.wxi"
             Query="//processing-instruction('define')[starts-with(., &quot;ProductVersionMajor=&quot;)]">
      <Output TaskParameter="Result" ItemName="Peeked" />
    </XmlPeek>

    <Message Text="@(Peeked)"/>

  </Target>

</Project>

我已经把它归结为

<?define ProductVersionMajor = "1" ?>

但目标是

1

任何帮助如何调整XPath查询高度赞赏。另外,使用占位符“ProductVersionMajor * =”而不是两次使用XmlPeek会很棒。


<XmlPeek XmlInputPath="ProductVersion.wxi"
Query="substring-before(substring-after(//processing-instruction(&quot;define&quot;)[starts-with(., &quot;ProductVersionMajor=&quot;)],&quot;),&quot;)">
  <Output TaskParameter="Result" ItemName="Peeked" />
</XmlPeek>

不幸的是只产生了一个

错误MSB3734:XPath查询“substring-before(substring-after(// processing-instruction(”define“)[starts-with(。,”ProductVersionMajor =“)],”),“)”无法加载。 'substring-before(substring-after(// processing-instruction(“define”)[starts-with(。,“ProductVersionMajor =”)],“),”)'有一个无效的令牌。

假设XmlPeek可能需要更多自定义XPath语法?


是。也尝试过。现在也试过了

Query="substring-before(substring-after(//processing-instruction('define')[starts-with(., 'ProductVersionMajor =')],&apos;&quot;&apos;),&apos;&quot;&apos;) ">

也没有成功。错误是

错误MSB4018:“XmlPeek”任务意外失败。\ r 错误MSB4018:System.Xml.XPath.XPathException:表达式必须求值为节点集。\ r \ n 错误MSB4018:在System.Xml.XPath.XPathNavigator.Select(XPathExpression expr)\ r \ n 错误MSB4018:在Microsoft.Build.Tasks.XmlPeek.Execute()\ r \ n 错误MSB4018:在Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.Execute()\ r \ n 错误MSB4018:在Microsoft.Build.BackEnd.TaskBuilder.ExecuteInstantiatedTask(ITaskExecutionHost taskExecutionHost,Task LoggingContext taskLoggingContext,TaskHost taskHost,ItemBucket bucket,TaskExecutionMode howToExecuteTask,Boolean&amp; taskResult)

2 个答案:

答案 0 :(得分:1)

从xpath的角度构建以下内容:

Query='substring-before(
    substring-after(
         //processing-instruction("define")[starts-with(., "ProductVersionMajor =")]
         ,
         &apos;&quot;&apos;
         )
         ,
    &apos;&quot;&apos;
    )' 

答案 1 :(得分:0)

我用这种方法解决了这个问题。希望它有所帮助:

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

  <UsingTask TaskName="GetWixDefine"
             TaskFactory="CodeTaskFactory"
             AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">

    <ParameterGroup>
      <File ParameterType="System.String" Required="true" Output="false" />
      <DefineName ParameterType="System.String" Required="true" Output="false" />
      <Value ParameterType="System.String" Output="true" />
    </ParameterGroup>

    <Task>
      <Reference Include="System.Xml" />
      <Using Namespace="System" />
      <Using Namespace="System.Text.RegularExpressions" />
      <Using Namespace="System.Xml" />

      <Code Type="Fragment" Language="cs">
        <![CDATA[
          this.Value = string.Empty;

          XmlDocument xmlDoc = new XmlDocument();
          xmlDoc.Load(this.File);
          string selector = string.Format("//processing-instruction('define')[starts-with(., '{0}')]", this.DefineName);
          XmlNode defineNode = xmlDoc.SelectSingleNode(selector);
          if (defineNode == null)
            throw new Exception("define not found");

          string regex = string.Format("{0}[ ]*=[ ]*\"(?<value>.*)\"", DefineName);
          Match match = Regex.Match(defineNode.InnerText, regex);
          if (!match.Success)
            throw new Exception("cannot match correctly");

          this.Value = match.Groups["value"].Value;
        ]]>
      </Code>
    </Task>

  </UsingTask>

  <Target Name="BeforeBuild">
    <GetWixDefine File="VersionFile.wxi" DefineName="ProductVersion">
      <Output TaskParameter="Value" ItemName="ProductVersionValue"/>
    </GetWixDefine>
    <Message Importance="High" Text="ProductVersion: @(ProductVersionValue)"/>
  </Target>
</Project>