Modifying Cordova config.xml at Build Time

December 15th 2017 Cordova XSLT Ionic Framework

Cordova config.xml file contains some information that might be different between the test and the production builds of your application, e.g. preference values or even the application id. This could be solved by having a separate branch in source control with these changes, but you could also modify the values just before you start the build on the build server.

Since config.xml is just an XML file, it makes sense to write an XSLT transformation to modify the file. It's a proven technology that has good tooling available on every platform. Even if you don't have any previous experience with XSLT, it's easy enough to learn the basics needed for changing a couple of values.

The starting point is a transformation, which will just copy the full contents of the file verbatim:

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

From this starting point we can add a template to match a specific attribute using XPath and change its value, e.g. the id attribute of the widget element:

<xsl:template match="widget/@id">
  <xsl:attribute name="id">
    <xsl:value-of select="'com.damirscorner.myapp'"/>
  </xsl:attribute>
</xsl:template>

This won't work though, because of the default namespace in the config.xml. To make it work, we need to specify that namespace for XPath in the root node of the XSLT file and use the prefix in the pattern:

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:widget="http://www.w3.org/ns/widgets">
  <xsl:template match="widget:widget/@id">
    <xsl:attribute name="id">
      <xsl:value-of select="'com.damirscorner.myapp'"/>
    </xsl:attribute>
  </xsl:template>

As long as we're only changing attribute values, that's enough. If we want to change the value of an element with the default namespace, we also need to declare that namespace as default in the replacement node. Not using the prefix will avoid adding the prefix to the output file. The following template would change the application name for example:

<xsl:template match="widget:widget/widget:name">
  <name xmlns="http://www.w3.org/ns/widgets">My App Name</name>
</xsl:template>

For non-default namespaces we can simply declare the namespace in the XSLT root node with the same prefix as in config.xml and use that prefix, e.g.:

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:widget="http://www.w3.org/ns/widgets"
                xmlns:mfp="http://www.ibm.com/mobilefirst/cordova-plugin-mfp">
  <xsl:template match="widget:widget/mfp:server">
    <mfp:server runtime="mfp2" url="https://mfp.damirscorner.com" />
  </xsl:template>

You can easily test the XSLT transformation online on pages like this one. To run it as a part of the build process, you can use a command line tool.

On Windows you can use PowerShell:

$xslt = New-Object System.Xml.Xsl.XslCompiledTransform
$xslt.Load('C:\WorkingDir\transform.xslt')
$xslt.Transform('C:\WorkingDir\config.xml', 'C:\WorkingDir\config.out.xml')

On Linux, you can simply invoke the xsltproc command-line utility:

xsltproc ./transform.xslt ./config.xml > ./config.out.xml

Since you can't overwrite the input file directly, you will need to copy the output file over the source file before starting the rest of the build.

Copyright
Creative Commons License