2
votes

I have directory with subdirs with xml files in it with different extensions.


Start of updated part


Target dir: /some/path

Target files mask: *.load

Basic filterset we use to find *.load files under /some/path:

<fileset dir="/some/path">
    <include name="**/*.load" />
</fileset>

There could by multiple subdirs under /some/path and multiple *.load files also.

But we need to enhance filtering based on XML content and params described in examples, use cases below.

Examples:

load_file1.load:

<load 
    id="0a0740d1fc1a33a28f1397b76cae48bc"
    order="9"
    enable="true"
    name="Load name 1"
    type="LoadType.custom">
    <parent />
    <default-property name="Property2"
                      type="java.lang.Integer"
                      value="0" />
    <default-property name="Property1"
                      type="java.lang.Boolean"
                      value="false" />
</load>

load_file2.load:

<load 
      id="ec9ca08d11ca34b42e13c5f21578d82c"
      name="Load name 2"
      order="0"
      enable="true"
      type="LoadType.base">
    <parent />
    <default-property name="Load name 1"
                      type="java.lang.String"
                      value="test3" />
    <default-property name="Property2"
                      type="java.lang.Integer"
                      value="0" />
    <!-- here could be any number of other sub-properties  -->
    <date-range end-date="1/31/1900"
                     start-date="1/31/1900" />
</load>

Input data:

Ant param: Load_name = "Load name 1" - used to find corresponding files

Ant param: Load_param_name_replace = "enable"

Ant param: Load_param_value_replace = "false"

NB! We always search for files based on value of //load/@name attribute (hardcoded) inside them:

<load 
      id="ec9ca08d11ca34b42e13c5f21578d82c"
      name="Load name 2"
      order="0"
      enable="true"
      type="LoadType.base">

Problem (based on example of files above):

  1. We should find files where //load/@name = $Load_name ANT param ("Load name 1")

  2. We should change in found files (could be multiple) XML attribute declared in $Load_param_name_replace ANT param ("enable") value to value of ANT param $Load_param_value_replace ("false")

Expected results:

  1. File(s) is found: load_file1.load

NB! please pay attention that in load_file2.load we have <default-property name="Load name 1" ... that match combination name="Load name 1", but we need to distinguish between this invalid case and valid one in file load_file1.load.

  1. In found file(s) load_file1.load XML attribute defined in $Load_param_name_replace ("enable") ANT param under //load node should be changed to new value defined in ANT param $Load_param_value_replace ("false")

So after ANT task the file load_file1.load should look as:

<load 
    id="0a0740d1fc1a33a28f1397b76cae48bc"
    order="9"
    enable="false"
    name="Load name 1"
    type="LoadType.custom">
    <parent />
    <default-property name="Property2"
                      type="java.lang.Integer"
                      value="0" />
    <default-property name="Property1"
                      type="java.lang.Boolean"
                      value="false" />
</load>

End of updated part


As you can see xml files content is spread through multiple lines - that is the tricky part for me.

We tried ANT fileset target with containsregexp filters where searched for multiline regex with name="load_name1" but without success. We used multiline=true and singleline=true - didnt work either.

After that we tried XMLtask - but there were not enough examples of how to replace xml property in multiple .XML files based on some fileset.

So if you could provide a couple of examples - it'd be greatful!

2

2 Answers

1
votes

Completely revised after updated problem description :

<project>
<taskdef name="xmltask" classname="com.oopsconsultancy.xmltask.ant.XmlTask"/>

<property name="editno" value='&lt;default-property name="Load name 1"'/>
<property name="edityes" value='name="Load name 1"'/>
<property name="editxpath" value="//load/@enable"/>
<property name="editnew" value="false"/>

 <xmltask todir="/some/path" report="true">
  <fileset dir="/some/path">
   <include name="**/*.load"/>
    <not>
     <contains text="${editno}" casesensitive="true"/>
    </not>
    <contains text="${edityes}" casesensitive="true"/>
   </fileset>
   <replace path="${editxpath}" withText="${editnew}"/>
  </xmltask>
</project>

for a quick check of the contents of a fileset simply use the builtin property ${toString:filesetid}

 <fileset dir="/some/path" id="foobar">
  <include name="**/*.load" />
  <not>
   <contains text="${editno}" casesensitive="true" />
  </not>
  <contains text="${edityes}" casesensitive="true" />
 </fileset>

 <echo>${toString:foobar}</echo>

see Ant manual Properties and PropertyHelpers

1
votes

Use the Ant XSLT task to apply a transform like the following:

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

    <xsl:template match="load[@name='load_name1']">
        <xsl:copy>
            <xsl:attribute name="from">date2</xsl:attribute>
            <xsl:apply-templates select="@*[name()!='from']"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

This makes a copy of your input, replacing the from attribute on the tags matching name="load_name1". Note that this may change the indentation, but will work no matter how the input is formatted, which may not be possible with regular expressions.