how to do for loop based on a limit in Ant - ant-contrib

In Ant-contrib, we can do something like:
<for list="a,b,c,d" param="instence">
But if I don't have a list, I only have a limit, e.g. limit=4.
Is there a way to do for loop based on limit, like:
<for limit="4" param="index">

<project name="Attachments" default="print">
<property name="numAttachments" value="20" />
<target name="generate">
<script language="javascript"><![CDATA[
var list = '1';
var limit = project.getProperty( "numAttachments" );
for (var i=2;i<limit;i++)
{
list = list + ',' + i;
}
project.setNewProperty("list", list);
]]>
</script>
</target>
<target name="print" depends="generate">
<for list="${list}" param="letter">
<sequential>
<echo>Letter #{letter}</echo>
</sequential>
</for>
</target>
</project>

Its not exactly what you want, but this page has an example. Essentially, you pass in the limit as a list of numbers. Its not elegant, but it works.
Here's another idea - see the answer by user "cn1h". Its a cool way to get around limitations in ANT - embed a script from another language which can do what you want. Nice!

In antcontrib you can also do:
<for param="index" end="#{numberOfIterations}" start="1">
But be aware of a bug: It is unable to handle
begin and end being the same. So when "numberOfIterations" equals 1 you get an error.
We got a workaround for this, checking the value of numberOfIterations first and only when its not 1 doing the for-statement.
<if><equals arg1="1" arg2="#{numberOfIterations}"/>
<then>
....
</then>
<else>
<for param="index" end="#{numberOfIterations}" start="1">
....
</else>
</if>

The Ant addon Flaka provides some solutions for your problem.
1) Use a while loop
the test attribute evaluates some EL expression, which maybe a simple counter, f.e.
<project name="demo" xmlns:fl="antlib:it.haefelinger.flaka">
<!-- some counter -->
<fl:let>
countdown = 3
</fl:let>
<fl:while test=" countdown >= 0 ">
<fl:echo>
#{countdown > 0 ? countdown : 'bang!' }..
</fl:echo>
<fl:let>
countdown = countdown - 1
</fl:let>
</fl:while>
</project>
output:
[fl:echo] 3..
[fl:echo] 2..
[fl:echo] 1..
[fl:echo] bang!..
or some other expression, f.e. checking for existence of a file, means looping until some file exists :
<fl:while test=" !'/home/rosebud/stop'.tofile.isfile ">
<fl:echo>
still working..
</fl:echo>
</fl:while>
2) Use a for loop with break or continue :
<project name="demo" xmlns:fl="antlib:it.haefelinger.flaka">
<fl:for var="i" in=" list(1,2,3,4,5,6) ">
<fl:echo>i = #{i}</fl:echo>
<fl:break test=" i == 3 " />
</fl:for>
<fl:for var="i" in=" list(1,2,3,4,5,6) ">
<fl:continue test=" i > 3 " />
<fl:echo>i = #{i}</fl:echo>
</fl:for>
</project>
which gives the same result :
[fl:echo] i = 1
[fl:echo] i = 2
[fl:echo] i = 3
See more details in the Flaka manual

Related

find xml-nodes by tag with wildcard

I am trying to find any nodes in a xml whos tags start with a certain pattern.
<data>
<general>
<va value="400" /> <!--looking for this "v-tag"-->
<vb value="42" /> <!-- and this one-->
<y value="43" />
</general>
<special>
<va value="100" />
</special>
</data>
I cannot put together the xpath expression. Something like this
xyz = lxml.etree.parse( ... )
vees = xyz.xpath("general/[tag='v*']")
I would like to have vees beeing
vees
Out[64]: [<Element va at 0x....>, <Element vb at 0x...>]
Try changing:
vees = xyz.xpath("general/[tag='v*']")
to
doc.xpath('//general//*[starts-with(name(),"v")]')
and see if it works.

Counting an XML attribute in Groovy

So I'm making a script in Groovy that parses a really large XML file, appends some stuff and slightly changes each element every time it appends. Each of these elements has an ID number associated with it and I want to make it so that every time an element is appended, the ID number will = the highest ID number in the file +1. I'll show a little piece of code to that will help understand:
<?xml version="1.0" encoding="UTF-8"?>
<xliff xmlns="xyxy" version="1.1">
<file original="zzz.js" source-language="en" target-language="en" datatype="javascript">
<body>
<trans-unit id="20" resname="foo">
<source>foofoo</source>
<target>foofoo</target>
</trans-unit>
<trans-unit id="21" resname="blah">
<source>blahblah</source>
<target>blahblah</target>
</trans-unit>
</body>
</file>
</xliff>
In this case, if I added an element (trans-unit) to the list, the ID would need to be 22. I have an algorithm that parses and appends, but I'm not sure how to increment the ID each time. Again, I'm using Groovy to do this. Does anyone have an idea? Thanks in advance!!
Assuming you have parsed that XML with xmlslurper or xmlparser, you should be able to get the next id with the help of max:
def xml = '''<?xml version="1.0" encoding="UTF-8"?>
<xliff xmlns="xyxy" version="1.1">
<file original="zzz.js" source-language="en" target-language="en" datatype="javascript">
<body>
<trans-unit id="20" resname="foo">
<source>foofoo</source>
<target>foofoo</target>
</trans-unit>
<trans-unit id="21" resname="blah">
<source>blahblah</source>
<target>blahblah</target>
</trans-unit>
</body>
</file>
</xliff>'''
def x = new XmlSlurper().parseText(xml)
def next = 1 + x.file.body.'trans-unit'*.#id*.text().collect { it as Integer }.max()
assert next == 22
To use XmlParser, you need to change the line to:
def next = 1 + x.file.body.'trans-unit'*.#id.collect { it as Integer }.max()

Build a string in MSBuild as a concatenation of a base string n-times

I have a numer, "n" in a property in MSBuild. I also have a string "Str" that needs to be duplicated n-times to achieve a final string that is the repetition of "Str" n times.
Eg. If n is 3 and Str is "abc", what I want to obtain is "abcabcabc"
Since one cannot loop in MSBuild, I don't know how to achieve this. Perhaps with an item group, but how do I create one based on a property containing an "n" count?
Thanks!
To create a String repeated n times, you can also do this (at least in MSBuild Tools v4.0):
<SomeRepeatedString>$([System.String]::New("-", 40))</SomeRepeatedString>
usually for things like this I resolve to using inline C#, as it costs me less time than searching all over the internet to find a 'true' msbuild solution; here you go:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MyString>abc</MyString>
<Count>3</Count>
</PropertyGroup>
<UsingTask TaskName="RepeatString" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
<ParameterGroup>
<s ParameterType="System.String" Required="true" />
<n ParameterType="System.Int32" Required="true" />
<result ParameterType="System.String" Output="true" />
</ParameterGroup>
<Task>
<Code Type="Fragment" Language="cs"><![CDATA[
result = string.Concat( Enumerable.Repeat( s, n ) );
]]></Code>
</Task>
</UsingTask>
<Target Name="doit">
<RepeatString s="$(MyString)" n="$(Count)">
<Output PropertyName="result" TaskParameter="result" />
</RepeatString>
<Message Text="Result = $(result)"/>
</Target>
</Project>

Stored procedure not executed when string is empty

I've got a really weird problem and I can't seem to find a solution to it. I've got an SqlDataSource with a set of parameters and a select command in form of a stored procedure. One of the parameters is a string called #SearchPhrase which gets its value from a textbox that when left empty is suppose to return all posts. The parameter gets its value via a search button that first set the value of searchBox.Text.Trim() to the #SearchPhrase and then databinds a gridview that displays the search result.
The stored procedure works fine and returns the result as long as a value is entered in the textbox but when left empty it turns out the stored procedure is never executed. I know this because I've added a line to it that stores all of the parameters inserted every time it's called.
How come I can't get it to run without entering something in the textbox? The only way I can get it to execute is to enter a blank space and pass " " to the stored procedure and after that do a left and right trim on it. Why not when passing a string with length = 0?
Here's the code for the datasource and the assigning of the parameters. It's only the #SearchPhrase parameter that is causing the problem, the rest work just fine. The first three lines of the click event (the commented) is the somewhat ugly way to go if I want to assign a " " and that way make it work.
<asp:SqlDataSource ID="enterprisesDS" runat="server"
ConnectionString="<%$ ConnectionStrings:CRMdb %>"
SelectCommand="entGetEnterprises" SelectCommandType="StoredProcedure">
<SelectParameters>
<asp:Parameter Name="SearchPhrase" Type="String" />
<asp:Parameter Name="IsActive" Type="Boolean" DefaultValue="true" />
<asp:Parameter Name="Country" Type="Byte" />
<asp:Parameter Name="LocalReference" Type="String" />
<asp:Parameter Name="Class" Type="String" />
<asp:Parameter Name="LocationID" Type="Byte" />
</SelectParameters>
</asp:SqlDataSource>
protected void search_Click(object sender, EventArgs e)
{
//string searchPhrase = " ";
//if (searchBox.Text.Trim().Length > 0)
// searchPhrase = searchBox.Text.Trim();
enterprisesDS.SelectParameters["SearchPhrase"].DefaultValue = searchBox.Text;
enterprisesDS.SelectParameters["Country"].DefaultValue = countries.SelectedValue;
enterprisesDS.SelectParameters["LocalReference"].DefaultValue = localReferences.SelectedValue;
enterprisesDS.SelectParameters["Class"].DefaultValue = classes.SelectedValue;
string locID = "0";
if (locations.SelectedValue != null)
locID = locations.SelectedValue;
enterprisesDS.SelectParameters["LocationID"].DefaultValue = locID;
enterprises.DataBind();
}
Could this be it? CancelSelectOnNullParameter property on the SqlDataSource.
SqlDataSource and stored procedure call issue

access ant property value for pattern variable in file.eachFileMatch() in Groovy

I am unable to run the code for moving file, when i use the ant macrodef attribute in groovy task inside the macrodef.
<macrodef name="dirmove">
<attribute name="todir" />
<attribute name="fromdir" />
<attribute name="includes" default="*" />
<sequential>
<var name="todir" value="#{todir}" />
<var name="fromdir" value="#{fromdir}" />
<var name="includes" value="#{includes}" />
<groovy>
File dir1 = new File(properties.'fromdir');
File dir2 = new File(properties.'todir');
def pattern = properties.get('includes')
println pattern;
dir1.eachFileMatch ~/pattern/, {
f->
boolean fileMoved = f.renameTo(new File(dir2, f.getName()));
//assert f.name == '1.txt' //**because File object is immutable, so I am just checking for the existing of previous file name. It is still there.
println fileMoved;
}
</groovy>
</sequential>
</macrodef>
This code correctly prints the value of pattern, which is coming from attribute value. But the eachFileMatch function doesn't picks up the spec
dir1.eachFileMatch ~/pattern/, {
should be
dir1.eachFileMatch ~/${pattern}/, {
As pattern is a String variable, so you need to add it in to the regex pattern as such.
Previously, you were just searching for all files called pattern

Resources