2

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

1

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

Sign up to request clarification or add additional context in comments.

8 Comments

thx for example provided. One more point - we can't just validate that string "name='value'" exists in XML file because its structure could be more tricky and we could have some other node, not just root one <load> with key-value like "name='value'". So we want to be sure, that we check that param exactly for root node.
I updated example in a question. That is why we tried regex inside <fileset> first.
your updated more tricky example is a bit confusing : [1.]\\load\@name is no valid xpath expression, the valid expression //load/@name would yield load_name2 [2.] you search for name="whatever" only as attribute from load tag but not as attribute from property tag, right ?
Or does your updated more tricky example mean combine those two xml snippets ending up with a xmlsnippet containing two load tags, where the second one has a nested section with multiple property tags ?
Sorry for confusion - I updated xpath and provide a comment. Tricky it is about that properties could be nested to <load> node.
|
1

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.

2 Comments

Thx for example. We give this a try also!
@zmische - To use this stylesheet with your more tricky example, you will have to change the "apply-templates" to <xsl:apply-templates select="@*[name()!='from']|node()"/> (added |node() to select). You would also have to change "load_name1" in the predicate to "load_name2".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.