Version 4

    See also: Changing AS 7 configuration (standalone.xml) with XSLT template from Maven

     

    Ideal tool to programatically change XML files is XSLT.

    This article shows how to use it with JBoss AS.

    I assume that you're familiar with XSLT.

     

    Let's take an example from the AS 7 testsuite. We needed to change the datasource configuration to run agains various databases.

    For that purpose, this XSLT template was created:  https://github.com/jbossas/jboss-as/blob/master/testsuite/integration/src/test/xslt/changeDatabase.xsl

     

     

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                    xmlns:ds="urn:jboss:domain:datasources:1.0" version="1.0">
        <xsl:output method="xml" indent="yes"/>
    
        <xsl:param name="ds.jdbc.driver.jar" select="'fred'"/>
        <xsl:param name="ds.jdbc.url" select="'wilma'"/>
        <xsl:param name="ds.jdbc.user" select="'test'"/>
        <xsl:param name="ds.jdbc.pass" select="'test'"/>
    
        <xsl:variable name="newDatasourceDefinition">
            <ds:datasource jndi-name="java:jboss/datasources/ExampleDS" pool-name="MSQL" enabled="true" jta="true"
                           use-java-context="true">
                <ds:connection-url><xsl:value-of select="$ds.jdbc.url"/></ds:connection-url>
                <ds:driver><xsl:value-of select="$ds.jdbc.driver.jar"/></ds:driver>
                <ds:security>
                    <ds:user-name><xsl:value-of select="$ds.jdbc.user"/></ds:user-name>
                    <ds:password><xsl:value-of select="$ds.jdbc.pass"/></ds:password>
                </ds:security>
            </ds:datasource>
        </xsl:variable>
    
        <!-- replace the old definition with the new -->
        <xsl:template match="//ds:subsystem/ds:datasources/ds:datasource[@jndi-name='java:jboss/datasources/ExampleDS']">
            <!-- http://docs.jboss.org/ironjacamar/userguide/1.0/en-US/html/deployment.html#deployingds_descriptor -->
            <xsl:copy-of select="$newDatasourceDefinition"/>
        </xsl:template>
    
        <!-- get rid of the default driver defs -->
        <xsl:template match="//ds:subsystem/ds:datasources/ds:drivers"/>
    
        <!-- Copy everything else. -->
        <xsl:template match="@*|node()">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:template>
    
    </xsl:stylesheet>
    

     

    The <xsl:param ...> are declaration of template's parameters. Their value (passed from maven-xml-plugin in our case) is accessible as $param.name .

     

    XSLT may store whole XML subtrees in variables. We leverage that in <xsl:variable ...> , where we create a new datasource definition.

     

    Notice the <ds: prefix in all elements of the datasource. This corresponds with the fact that AS7 modules configuration in standalone.xml uses custom elements from given module's namespace.

    In this case, datasources module uses namespace "urn:jboss:domain:datasources:1.0", for which we define a shortcut "ds" in this XSLT (following the convention from standalone.xml).

     

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                    xmlns:ds="urn:jboss:domain:datasources:1.0" version="1.0">
    

     

    Unfortunately, the XSLT processor Xalan replaces the ds: prefix with whole namespace in the resulting XML file. But that's a cosmetic defect; otherwise it's works well.

     

    This part replaces

    <xsl:template match="//ds:subsystem/ds:datasources/ds:datasource[@jndi-name='java:jboss/datasources/ExampleDS']">
    

     

    XSLT processing works in steps. In each step, the processor has a "current" set of nodes, to which it applies the best matching template (or skips it if there's no matching template).

    Which template matches is defined by the match="..." param, which contains an XPath expression. Simply said, the template with the most complex matching XPath is selected.

    That is used in the following "catch-all" template - it is matches all attributes or nodes, but has least specific XPath, therefore other templates take precedence.

     

        <!-- Copy everything else. -->
        <xsl:template match="@*|node()">
    

     

    The content of the "current" node is replaced with the content of the template; within the template, you can use few features, like <xslt:copy-of> or <xslt:copy> - examples are in this template.