Using filename in xmltask sections at runtime

Xmltask is a valuable extension to Apache ANT for processing XML files. It is possible to apply one same task to multiple XML-files using wildcards in the attribute source of xmltask or by using the type. The capability of using wildcards in the attribute source will be deprecated, so it would be wise to anticipate on this by using using the type when using wildcards. When processing multiple files using xmltask it would be nice to have the name of the file being processed at runtime, however xmltask does not supply a way to extract or use this filename as a property. You can workaround this is by using a separate target looping through the files in the file set and calling your xmltask target for each of the files in the file set passing the filename as a parameter.

The following example is a sample from a Oracle 10G BPEL/ESB to SCA upgrade script. The targets shown do delete the import statements from DB Adapter WSDL files which have been removed from the composite after migration of a 10G BPEL service to 11G. The target post_process_WSDLs selects all WSDL files in a directory defined in the property composite.home. For each file the target post_upgrade_remove_db_header_import is called with the parameter xmlfile containing the selected file from the fileset.

<!--  
      target       : post_process_WSDLs
      objective    : Post process WSDL files 
      parameters   : none
-->
  <target name="post_process_WSDLs">
    <echo>Post processing WSDLs</echo>
    <!-- call target post_upgrade_remove_db_header_import for each wsdl file in composite home -->
    <echo>Checking WSDLs for import statemens for non existing WSDL locations of DB headers</echo>
    <foreach param="xmlfile" target="post_upgrade_remove_db_header_import">
      <path>
        <fileset dir="${composite.home}" includes="*.wsdl"/>
      </path>
    </foreach>
  </target>

When the target post_upgrade_remove_db_header_import is called a file set type is used to select the file which is passed through the parameter xmlfile. The actions enclosed in the call section are performed on all elements like in the example below.

   <import namespace="http://xmlns.oracle.com/pcbpel/adapter/db/" location="DBAdapterOutboundHeader.wsdl"/>

For each import element the name of the imported wsdl is retrieved from the location attribute and tested on availability in the composite. When the wsdl file is not available, the import element is removed. Removal of the import element is done by another xmltask starting at line 25 nested into the call section. Here it is useful to have the name of the file being processed in the outer xmltask section starting at line 9. Watch the destbuffer for the xmltask at line 9 which is set to dev.null to prevent overwriting of the changes made in the xmltask at line 25.

<!--
      target       : post_upgrade_remove_db_header_import
      objective    : remove import statements of non-existing WSDL files with 
                     namepace http://xmlns.oracle.com/pcbpel/adapter/db/
      parameters   : wsdlName ; filename of the WSDL
-->
  <target name="post_upgrade_remove_db_header_import">
    <basename property="wsdlName" file="${xmlfile}"/>
    <echo>Checking WSDL ${wsdlName}</echo>
    <xmltask destbuffer="dev.null">
      <fileset dir="${composite.home}">
        <include name="${wsdlName}"/>
      </fileset>
      <call path="/*[local-name()='definitions']/*[local-name()='import' and @namespace='http://xmlns.oracle.com/pcbpel/adapter/db/']">
        <param name="location" path="@location"/>
          <actions>
            <if>
              <available file="${composite.home}/@{location}" type="file"/>
              <then>
                <echo message="Imported WSDL @{location} exists"/>
              </then>
              <else>
                <echo message="Imported WSDL @{location} does not exist"/>
                  <trycatch>
                    <try>
                      <xmltask todir="${composite.home}" failWithoutMatch="true">
                        <fileset dir="${composite.home}">
                          <include name="${wsdlName}"/>
                        </fileset>
                        <remove path="/*[local-name()='definitions']/*[local-name()='import' and @namespace='http://xmlns.oracle.com/pcbpel/adapter/db/' and @location='@{location}']"/>
                      </xmltask>
                      <echo message="Removed import of WSDL @{location}"/>
                    </try>
                    <catch>
                      <echo message="Warning: Failed to removed import of WSDL @{location}"/>
                    </catch>
                  </trycatch>
              </else>
            </if>
          </actions>
      </call>
    </xmltask>
  </target>

Just another example which replaces the ora namespace alias for parseXML Xpath extensions in a BPEL file with the namespace alias oraext and adds the namespace declaration of the new alias as an attribute in the process element.

<!--	
      target       : post_upgrade_update_parsexml_namespace
      objective    : replace namespace alias for xpath extension parseXML with
                     new namespace alias and add ns alias definion in process element
      parameters   : bpelName ; filename of the BPEL file
-->
<target name="post_upgrade_update_parsexml_namespace">
  <basename property="bpelName" file="${bpelFile}"/>
    <echo>Updating parseXML namespace in ${bpelName}</echo>
    <xmltask destbuffer="dev.null">
    <fileset dir="${composite.home}">
      <include name="${bpelName}"/>
    </fileset>
    <!-- for each expression attribute calling parseXML extension -->
    <call path="//@*[local-name()='expression' and substring(substring-after(.,':'),1,8) = 'parseXML' ]">
      <param name="oldLocation" path="."/>
      <actions>
        <!-- old alias -->
        <propertyregex property="oldAlias" input="@{oldLocation}" regexp="(.*HappyparseXML.*"
        select="\1" casesensitive="true" override="true"/>
        <!-- new location -->
        <propertyregex property="newLocation" input="@{oldLocation}"
        regexp="(.*)${oldAlias}(.*)" select="\1oraext:\2" casesensitive="true"
        override="true"/>
        <!-- replace xml with new local namespace -->
        <replace file="${bpelFile}" value="${newLocation}">
          <replacetoken>@{oldLocation}</replacetoken>
        </replace>
      </actions>
    </call>
  </xmltask>
  <!-- insert namespace alias oraext -->
  <xmltask source="${bpelFile}" dest="${bpelFile}">
    <attr
    path="/*[local-name()='process' and namespace-uri()='http://schemas.xmlsoap.org/ws/2003/03/business-process/']"
    attr="xmlnsGaspraext"
    value="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.ExtFunc"
    />
  </xmltask>
</target>

blog comments powered by Disqus