Copy one value over to another with xmltask - parsing

Is it possible for an xml task to copy the value of one node into another node for each element in a list?
Source XML:
<a>
<b>
<c1>foo</c1>
<c2></c2>
</b>
<b>
<c1>bar</c1>
<c2></c2>
</b>
...
</a>
Destination XML:
<a>
<b>
<c1>foo</c1>
<c2>foo</c2>
</b>
<b>
<c1>bar</c1>
<c2>bar</c2>
</b>
...
</a>
I'm trying to accomplish the above in my ant task, but I con't seem to find a way to do it, here is what I am doing so far,
<target name="mergefile">
<!-- Read the source into a buffer -->
<xmltask source="source.xml" clearBuffers="list">
<copy path="/a" buffer="list" append="true"/>
</xmltask>
<!-- Write them to the output -->
<xmltask source="destination.xml" dest="destination.xml"
outputter="simple">
<!-- First clear all the old paths. -->
<remove path="/a/b"/>
<!-- Then add the resolved ones. -->
<paste path="/a" buffer="list"></paste>
<!-- Copy the value over? -->
<replace path="a/b/c2/text()" withText="No Idea"/>
</xmltask>
</target>
Any idea of how to copy the value from one node to the next for all the elements in the list?

As, I guess, is usually the case, writing my own task was the only way I could see to do it.
#Override
public void execute() throws BuildException {
//Read file line by line, regex test on each line,
//matches get written back twice.
}
Then calling it was,
<copyregmatch file="myfile.xml" regex=".*replace.*" />

Related

How to concatenate paths returned from `fileset` into the XML file?

I'm trying to concatenate an unknown number of HTML files into one XML file.
That's no problem with:
<concat destfile="${temp.dir}/file.xml" encoding="UTF-8" outputencoding="UTF-8">
<fileset dir="${html.dir}" includes="**/*.html" />
</concat>
Now what I would like to do is, for each file of the fileset, insert its path into the concatenated file.
Example
I have the following HTML files in C:\whatever\sources:
A.html
B.html
In the result XML file, I'd like to get:
<allfiles>
<html url="C:\whatever\sources\A.html>...content of A.html...</html>
<html url="C:\whatever\sources\B.html>...content of B.html...</html>
</allfiles>
Is there a way to do that simply without reinventing the wheel and if possible without using ant-contrib?
As mentioned, you can use a scriptfilter inside filterchain task to run Javascript inside your Ant build.
For example:
<concat destfile="${temp.dir}/file.xml" encoding="UTF-8" outputencoding="UTF-8">
<fileset dir="${html.dir}" includes="**/*.html" id="my-files"/>
<filterchain>
<tokenfilter>
<filetokenizer />
<scriptfilter language="javascript" byline="false"><![CDATA[
content = self.getToken();
// Modify content of token.
//content=content.replaceAll("(?s)/\\*.*?\\*/","");
self.setToken(content);
]]></scriptfilter>
</tokenfilter>
<striplinecomments>
<comment value="//"/>
</striplinecomments>
<striplinebreaks/>
</filterchain>
</concat>
Find more examples at:
JavaExplorer/blob/master/static/build.xml
Getting file name inside Ant copy task filter
Using Ant scriptfilter to count lines

Apache Ant add header & footer to EVERY file in concat job

I'm sure that this is trivial - but have been bashing my head against a wall
I'm trying to take a directory full of mustache templates (html files essentially) and combine them into one file - wrapping each one with a tag
Example:
File1 = <a>This is a Link</a>
File2 = <b>This is in bold</b>
I want the output to look like:
<script type="text/mustache" id="File1">
<a>This is a Link</a>
</script>
<script type="text/mustache" id="File2">
<b>This is in bold</b>
</script>
I'm using a concat task
<concat destfile="mustache.js" fixlastline="yes">
<fileset dir="." includes="**/*.mustache"/>
</concat>
but can't figure out how to get the script blocks to display
At first i thought about using concat somehow with header and footer but didn't find a working solution.
If you not shy away from using some Ant addon, here's a solution based on Flaka =
<project name="demo" xmlns:fl="antlib:it.haefelinger.flaka">
<!-- make standard ant tasks understand EL expressions -->
<fl:install-property-handler />
<!-- we use path instead of pure fileset because we need
absolute filenames for loadfile later in for loop -->
<path id="foo">
<fileset dir="/some/path" includes="**/*.mustache"/>
</path>
<!-- iterate over the path/fileset -->
<fl:for var="file" in="split('${toString:foo}', ':')">
<!-- unset property for next loop -->
<fl:unset>content</fl:unset>
<!-- load file contents to property -->
<loadfile property="content" srcFile="#{file}"/>
<echo file="/some/path/foobar/mustache.js" append="true">
<!-- the id attribute gets filled with the basename of the current fileitem -->
<![CDATA[<script type="text/mustache" id="#{replace(file, '$1' , '.+?(\w+)\..+' )}">
#{trim('${content}')}
</script>]]></echo>
</fl:for>
</project>
Note : 1. my leftmost notation within the echo task to avoid unnecessary blanks in the resulting file ! just write as in my example above and your file will look like your wanted output
2. the <![CDATA[...]]> is needed, otherwise you'll get some error like "echo doesn't support the nested "script" element."

Changing property value in Ant

I don't want to use propertyregex in the AntContrib task, but I need to modify a property. I am using the cabarc command (I can't get the <cab> task to work), and I need to strip out the drive name.
${basedir} = "D:\some\directory\blah\blah"
${cwd} = some\directory\blah\blah"
I need this in order to strip out the path in cabarc (but still using directories). I've ended up doing the following:
<!-- Create a property set with just basedir -->
<!-- Needed for loadproperties to work -->
<propertyset id="cwd">
<propertyref name="basedir"/>
</propertyset>
<loadproperties>
<propertyset refid="cwd"/>
<filterchain>
<tokenfilter>
<replaceregex pattern=".:\\"
replace="cwd="/>
</tokenfilter>
</filterchain>
</loadproperties>
That works, but it's a little complex and will be hard to maintain.
Is there an easier way to do this?
get into the groove ;-)
<groovy>
properties.'cwd' = properties.'basedir'[3..-1]
</groovy>
or with Ant Plugin Flaka :
<project xmlns:fl="antlib:it.haefelinger.flaka" name="World">
<!-- simple echo -->
<fl:echo>#{replace('${basedir}', '$1' , '.:\\\\(.+)' )}</fl:echo>
<!-- set property -->
<fl:let>cwd := replace('${basedir}', '$1' , '.:\\\\(.+)' )</fl:let>
</project>
Disclosure = i'm participating as committer in the Flaka project

other option at place of <bool> tag

<if>
<bool>
<isgreaterthan arg1="${abc}" arg2="${xyz}"/>
</bool>
</if>
when i am running the code, it's showing the error if doesn't support the nested "bool" element.
is there any other option is there at the place of bool which supported by if
The example works in antcontrib-1.0b2 but not the latest antcontrib-1.0b3
Found this after hitting a similar problem after an update
Ant Flaka is a new Ant Plugin that provides an innovative Expression Language which makes many scripting part obsolete. Beside that Flaka provides conditional and repetitive control structures like when, unless, while, for, choose, switch ..
Your if statement with Flaka would look like =
<project xmlns:fl="antlib:it.haefelinger.flaka">
<property name="digitA" value="42"/>
<property name="digitB" value="23"/>
<property name="wordA" value="abcd"/>
<property name="wordB" value="efgh"/>
<!-- compare of digits -->
<fl:when test=" '${digitA}' > '${digitB}' ">
<echo>${digitA} gt ${digitB}</echo>
</fl:when>
<!-- example with string compare in switch -->
<fl:switch value="${wordA}">
<cmp gt="${wordB}">
<echo>${wordA} gt ${wordB}</echo>
</cmp>
<cmp lt="${wordB}">
<echo>${wordA} lt ${wordB}</echo>
</cmp>
</fl:switch>
</project>
please see the comprehensive Flaka Manual for further details !
It looks like you're attempting to use the Antelope if task, as it (unlike the ant-contrib if) supports a nested bool element. But, the error message is indicative of the task not being defined correctly.
Check that you have the Antelope jar, and a suitable taskdef in your buildfile. I use this:
<taskdef resource="ise/antelope/tasks/antlib.xml"
classpath="path/to/AntelopeTasks_3.5.1.jar" />
For details of what the task supports, see the documentation linked to above.
You can use 'bool' tag within 'if' provided you use taskdef for "if" using the classname="ise.antelope.tasks.IfTask"
Eg:
<target name="compare"> <taskdef name="if" classname="ise.antelope.tasks.IfTask"/> <var name="abc" value="2" /> <var name="xyz" value="1" /> <if> <bool> <isgreaterthan arg1="${abc}" arg2="${xyz}"/> </bool> <echo message="${abc} is greater than ${xyz}" /> </if> </target>

Ant macrodef: Is there a way to get the contents of an element parameter?

I'm trying to debug a macrodef in Ant. I cannot seem to find a way to display the contents of a parameter sent as an element.
<project name='debug.macrodef'>
<macrodef name='def.to.debug'>
<attribute name='attr' />
<element name='elem' />
<sequential>
<echo>Sure, the attribute is easy to debug: #{attr}</echo>
<echo>The element works only in restricted cases: <elem /> </echo>
<!-- This works only if <elem /> doesn't contain anything but a
textnode, if there were any elements in there echo would
complain it doesn't understand them. -->
</sequential>
</macrodef>
<target name='works'>
<def.to.debug attr='contents of attribute'>
<elem>contents of elem</elem>
</def.to.debug>
</target>
<target name='does.not.work'>
<def.to.debug attr='contents of attribute'>
<elem><sub.elem>contents of sub.elem</sub.elem></elem>
</def.to.debug>
</target>
</project>
Example run:
$ ant works
...
works:
[echo] Sure, the attribute is easy to debug: contents of attribute
[echo] The element works only in restricted cases: contents of elem
...
$ ant does.not.work
...
does.not.work:
[echo] Sure, the attribute is easy to debug: contents of attribute
BUILD FAILED
.../build.xml:21: The following error occurred while executing this line:
.../build.xml:7: echo doesn't support the nested "sub.elem" element.
...
So I guess I need either a way to get the contents of the <elem /> into a property somehow (some extended macrodef implementation might have that), or I need a sort of <element-echo><elem /></element-echo> that could print out whatever XML tree you put inside. Does anyone know of an implementation of either of these? Any third, unanticipated way of getting the data out is of course also welcome.
How about the echoxml task?
In your example build file replacing the line
<echo>The element works only in restricted cases: <elem /> </echo>
with
<echoxml><elem /></echoxml>
results in
$ ant does.not.work
...
does.not.work:
[echo] Sure, the attribute is easy to debug: contents of attribute
<?xml version="1.0" encoding="UTF-8"?>
<sub.elem>contents of sub.elem</sub.elem>
Perhaps the XML declaration is not wanted though. You might use the echoxml file attribute to put the output to a temporary file, then read that file and remove the declaration, or reformat the information as you see fit.
edit
On reflection, you can probably get close to what you describe, for example this sequential body of your macrodef
<sequential>
<echo>Sure, the attribute is easy to debug: #{attr}</echo>
<echoxml file="macro_elem.xml"><elem /></echoxml>
<loadfile property="elem" srcFile="macro_elem.xml">
<filterchain>
<LineContainsRegexp negate="yes">
<regexp pattern=".xml version=.1.0. encoding=.UTF-8..." />
</LineContainsRegexp>
</filterchain>
</loadfile>
<echo message="${elem}" />
</sequential>
gives
$ ant does.not.work
...
does.not.work:
[echo] Sure, the attribute is easy to debug: contents of attribute
[echo] <sub.elem>contents of sub.elem</sub.elem>

Resources