0

I have a xml string with (among others) properties such as x-pos="NN" and y-pos="NN" where NN is a positive or negative number. I want to read every value and change it to its arithmetic product - evaluated #{NN * 15}, i.e. x-pos="3" will be changed to x_pos="45".

Thus I need something like this:

<ant-contrib:propertyregex  property="xval"
   input="${xmlfile.contents}"
   regexp="x-pos\s*=\s*&quot;([0-9\-]+)&quot;"
   replace="x-pos=&quot;_TRICKY_EXPR_EVALUATOR_{\1 * 15}&quot;"
   override="true" global="yes"/>

Or maybe I can somehow capture all the /x-pos\s*=\s*\"([0-9-]+)\"/ matches (just like in PHP preg_match_all function) and get them in a flaka list or - say - in string separated by ';'? Once I have it I can split it, and iterate through it to replace each value 'manually'.

Is there any other ant extensions that work with perl-like regular expressions? I learned about flaka and ant-contrib, but those can't help.

Thanks for your thoughts!

update: here is a hypotetic fragment of xml to parse:

<sprite name="timer" xref="" pos-x="25" pos-y="4" path="img/folder1/img1.jpg" />
<sprite name="timer1" xref="" pos-x="25" pos-y="4" offset-x="100" offset-y="10" path="img/folder1/img2.jpg" />
<control name="timer2" xref="" pos-x="25" pos-y="4" size="100" offset-y="10" path="img/folder1/img2.jpg" />
Tertium
  • 6,049
  • 3
  • 30
  • 51
  • For parsing xml you shouldn't use regexp. Use the xmltask (http://www.oopsconsultancy.com/software/xmltask/index.html) and get a list of all x-pos nodes via xpath. Afterwards it's easy to iterate over that list. Please edit your answer and show the xmlstructure and i'll post a solution. – Rebse Mar 08 '13 at 17:19
  • @Rebse, the point is that xml structure doesn't matter. It's a class of tasks, not a single one (not only for xml). I know the structure-specific solution using propertyregex - parse string by string and attribute by attribute. But it is not universal, it'd much more easier if there were some extension that can make flaka list(s). Anyway, i'd like to see your specific solution. So I'll update my question. – Tertium Mar 08 '13 at 19:48
  • finally i got time to post some example, see my answer - HTH – Rebse Mar 11 '13 at 21:40

2 Answers2

1

Maybe when using flaka already using :

 <!-- Activate flaka for all ant tasks -->
 <fl:install-property-handler/>

combined with :

#{ x * y}

will work for you somehow, didn't test it, as antcontrib is not installed on my machine.
The property handler allows to use EL expressions inside all ant tasks.

Here's a small example with a given file foo.xml, needs xmltask and flaka :

<whatever>
<sprite name="timer" path="img/folder1/img1.jpg" pos-x="25" pos-y="4" xref=""/>
<sprite name="timer1" offset-x="100" offset-y="10" path="img/folder1/img2.jpg" pos-x="26" pos-y="4" xref=""/>
<control name="timer2" offset-y="10" path="img/folder1/img2.jpg" pos-x="27" pos-y="4" size="100" xref=""/>
</whatever>

Editing foo.xml in place :

<project xmlns:fl="antlib:it.haefelinger.flaka">
 <!-- Activate flaka for all ant tasks -->
 <fl:install-property-handler/>
 <!-- Import XMLTask -->
 <taskdef name="xmltask" classname="com.oopsconsultancy.xmltask.ant.XmlTask"/>

 <!-- get a list with all pos-x attribute values -->
 <xmltask source="foo.xml">
   <copy path="//whatever/*/@pos-x" append="true" propertySeparator="," property="posxlist"/>
 </xmltask>
 <echo>$${posxlist} => ${posxlist}</echo>
 <fl:let>counter ::= 1</fl:let>
 <!-- for loop with xmltask editing foo.xml in place => source = dest -->
 <fl:for var="posx" in="split('${posxlist}', ',')">
   <xmltask source="foo.xml" dest="foo.xml" report="true">
     <!-- i.e. multiplicating value * 3 -->
     <attr path="//whatever/*[${counter}]" attr="pos-x" value="#{posx * 3}"/>
   </xmltask>
   <fl:let>counter ::= '${counter}' + 1</fl:let>
 </fl:for>
</project>

output :

  [xmltask] Cannot append values to properties
  [xmltask] Cannot append values to properties
  [xmltask] Cannot append values to properties
     [echo] ${posxlist} => 25,26,27
  [xmltask] Document -->
  [xmltask] <whatever>
  [xmltask] <sprite name="timer" path="img/folder1/img1.jpg" pos-x="75" pos-y="4" xref=""/>
  [xmltask] <sprite name="timer1" offset-x="100" offset-y="10" path="img/folder1/img2.jpg" pos-x="26" pos-y="4" xref=""/>
  [xmltask] <control name="timer2" offset-y="10" path="img/folder1/img2.jpg" pos-x="27" pos-y="4" size="100" xref=""/>
  [xmltask] </whatever>
  [xmltask] Document <--
  [xmltask] Document -->
  [xmltask] <whatever>
  [xmltask] <sprite name="timer" path="img/folder1/img1.jpg" pos-x="75" pos-y="4" xref=""/>
  [xmltask] <sprite name="timer1" offset-x="100" offset-y="10" path="img/folder1/img2.jpg" pos-x="78" pos-y="4" xref=""/>
  [xmltask] <control name="timer2" offset-y="10" path="img/folder1/img2.jpg" pos-x="27" pos-y="4" size="100" xref=""/>
  [xmltask] </whatever>
  [xmltask] Document <--
  [xmltask] Document -->
  [xmltask] <whatever>
  [xmltask] <sprite name="timer" path="img/folder1/img1.jpg" pos-x="75" pos-y="4" xref=""/>
  [xmltask] <sprite name="timer1" offset-x="100" offset-y="10" path="img/folder1/img2.jpg" pos-x="78" pos-y="4" xref=""/>
  [xmltask] <control name="timer2" offset-y="10" path="img/folder1/img2.jpg" pos-x="81" pos-y="4" size="100" xref=""/>
  [xmltask] </whatever>
  [xmltask] Document <--
BUILD SUCCESSFUL
Total time: 826 milliseconds

the warning 'Cannot append values to properties' originates from com.oopsconsultancy.xmltask.CopyAction line 80 to underline that properties in ant are immutable and may safely be ignored - or even better delete it from source and rebuild xmltask.jar

Rebse
  • 10,307
  • 2
  • 38
  • 66
  • Thaks for the solution. Though it is raw and doesn't cover many use-cases, I'd appreciate you've post it, xmltask looks new and promising for me. – Tertium Mar 12 '13 at 12:31
0

Here's a fragment of my own solution. I won't mark it as accepted, because it doesn't solve the general text-parse problem (like php's preg_match_all). But maybe someone find it interesting. It is a little bit messy - I use ant properties and flaka EL variables, but it illustrates how to use them together. Here's the code:

filename: process.xml

<!-- these includes are needed so that eclipse can load autocompletion base from plugins,
and they tell to ant where plugins' jars are (in 'ut' folder on the same level)-->
<taskdef uri="antlib:it.haefelinger.flaka" resource="it/haefelinger/flaka/antlib.xml" classpath="ut/ant-flaka.jar" />
<taskdef uri="antlib:net.sf.antcontrib" resource="net/sf/antcontrib/antlib.xml" classpath="ut/ant-contrib-1.0b3.jar" />

<!-- call: >> ant -Dfname="folder/with/xmls" -f process.xml correct-xmls -->
<target name="correct-xmls">
    <fl:install-property-handler />
    <property name="slashn" value="${line.separator}" />

    <!-- get xmls - only with existing root resprops element -->
    <fileset dir="${fname}" includes="**/*.xml" id="xml-classes">
        <contains text="&lt;resprops&gt;" />
    </fileset>

    <fl:for var="xn" in="split('${toString:xml-classes}', ';')">
        <fl:let>curfile = file(concat('${fname}','/',xn))</fl:let>
        <fl:let>tgtfile = file(concat('${fname}','/',xn,'.new'))</fl:let>
        <fl:echo>#{ format('file %s, last modified %tD, size: %d',  
            curfile.path, curfile.mtime, curfile.isdir ? 0 : curfile.size) }</fl:echo>

        <fl:unset>xmlfile.contents</fl:unset>
        <loadfile property="xmlfile.contents" srcFile="#{curfile}" />
        <fl:let>outstr = ''</fl:let>
        <fl:for var="str" in="split('${xmlfile.contents}', '\n')">
            <fl:unset> xval </fl:unset>
            <ac:propertyregex property="xval" input="#{str}" regexp="pos-x\s*=\s*&quot;([0-9\-]+)&quot;" select="\1" override="true" />
            <!-- force set property 'resstr' to value of var 'str'-->
            <fl:let>resstr ::= str</fl:let>

            <!-- process only if pos-x is found and we have its value in 'xval' -->
            <fl:when test="not empty '#{property.xval}'">
                <fl:let>outval = (property.xval * 15.5 + 0.5) </fl:let>
                <!-- kinda int-from-float -->
                <ac:propertyregex property="gotv" input="#{outval}" regexp="([0-9\-]+)\." select="\1" override="true" />
                <ac:propertyregex property="resstr"
                                  input="${resstr}"
                                  regexp="pos-x\s*=\s*&quot;([0-9\-]+)&quot;"
                                  replace="pos-x = &quot;#{gotv}&quot;"
                                  override="true"
                />
            </fl:when>

            <!-- add to output string by string -->
            <fl:let> outstr = format('%s%s%s', outstr , resstr, slashn) </fl:let>

        </fl:for>

        <!--save processed file -->
        <echo file="#{tgtfile}" encoding="utf-8">#{outstr}</echo>

    </fl:for>
</target>

Tertium
  • 6,049
  • 3
  • 30
  • 51
  • 1
    When it gets complicated you need a real programming language, use Groovy via task in ant => http://groovy.codehaus.org/The+groovy+Ant+Task – Rebse Mar 12 '13 at 21:30
  • at first sight looks like what I searching for, thanx, will keep in mind and bookmarks! – Tertium Mar 13 '13 at 22:32