Search code examples
xpathwixweb-configwindows-installerelement

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


I’m trying to change the version numbers of the following assembly.

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

The problem is I don’t know how to change the value in the bindingRedirect when I set Newtonsoft.Json as ElementPath. It’s also not possible to set the path to the bindingRedirect, because other assemblies could have the same versionnumber.

Thanks.

EDIT:

The string as in the comment of @Dialecticus would work. I tested this string online: https://www.freeformatter.com/xpath-tester.html But unfortunately it does not work with WiX. What I found in the documentation is that square brackets need to be escaped: https://wixtoolset.org/documentation/manual/v3/xsd/util/xmlconfig.html My XPath looks like this:

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

The problem here is the XML namespace in assemblyBinding. I removed it for testing and it worked. Also, I started the path with //dependentAssembly, but again I get the error: Failed to find node


Solution

  • XPath defines both the predicate (the filter) and the target. For you the target is newVersion attribute of node bindingRedirect and the predicate is name="Newtonsoft.Json" of node assemblyIdentity. Combining the two the target should look something like this:

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

    Unfortunately XmlFile element does not support namespaces. There is an open issue for it in GitHub, but it's old and inactive. The workaround is described in a post in wix mailing list:

    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/']