Wix 和 XPath:当路径不唯一时如何使用 util:XmlFile 更改版本号

Wix and XPath: How to change version number with util:XmlFile when the path is not unique

我正在尝试更改以下程序集的版本号。

  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" culture="neutral" publicKeyToken="30ad4fe6b2a6aeed"/>
        <bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0"/>
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Optimization" publicKeyToken="31bf3856ad364e35"/>
        <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="1.1.0.0"/>
      </dependentAssembly>

问题是当我将 Newtonsoft.Json 设置为 ElementPath 时,我不知道如何更改 bindingRedirect 中的值。也无法设置 bindingRedirect 的路径,因为其他程序集可能具有相同的版本号。

谢谢。

编辑:

@Dialecticus 评论中的字符串可以使用。我在线测试了这个字符串:https://www.freeformatter.com/xpath-tester.html 但不幸的是,它不适用于 WiX。我在文档中发现的是方括号需要转义:https://wixtoolset.org/documentation/manual/v3/xsd/util/xmlconfig.html 我的 XPath 如下所示:

//configuration/runtime/assemblyBinding/dependentAssembly[\[]assemblyIdentity/@name='Newtonsoft.Json'[\]]/bindingRedirect/@newVersion

这里的问题是 assemblyBinding 中的 XML 命名空间。我将其删除进行测试并且它有效。另外,我用 //dependentAssembly 开始路径,但我再次收到错误:找不到节点

XPath 定义谓词(过滤器)和目标。对你来说,目标是节点 bindingRedirectnewVersion 属性,谓词是节点 assemblyIdentityname="Newtonsoft.Json"。结合这两个目标应该看起来像这样:

/runtime/assemblyBinding/dependentAssembly[assemblyIdentity/@name='Newtonsoft.Json']/bindingRedirect/@newVersion

很遗憾,XmlFile 元素不支持命名空间。 Wix 邮件列表中有一个 open issue for it in GitHub, but it's old and inactive. The workaround is described in a post

If you have <foo><bar xmlns="http://example.com/"><quux/></bar></foo>, the XPath expression /foo/bar/quux won't match, because it's asking for namespace-less elements, and both bar and quux are in a namespace.

It seems WiX doesn't support declaring namespace prefixes to be used in the XPath expression, so you'd have to use the ugly /foo/*[local-name() = 'bar']/*[local-name() = 'quux']. Or, if you want to make sure it only applies to an element in the right namespace, *[local-name() = 'foo' and namespace-uri() = 'http://example.com/']