Ant: How to check (programatically) if schemavalidate was successful or not - ant

I would like to know if is possible to check/capture the result of a "schemavalidate"/"xmlvalidate" operation?
The idea is to parse the files in a folder, try to validate each of them against an XSD and get the status of the operation in a property (eventually, output the status and the result of the operation in a log file).
The status of the validation can be then checked in order to know if some other tasks should be performed or not on that particular XML file.
For example:
<target name="convert-user-folder">
<echo>${user.folder}</echo>
<!-- Iterate all XML files in the folder -->
<foreach target="validate-xml-file" param="user.input.xml">
<path>
<fileset dir="${user.folder}">
<include name="*.xml" />
</fileset>
</path>
</foreach>
</target>
<target name="validate-xml-file">
<echo message="Validating ${user.input.xml}"/>
<!-- Checking if XML is well formed -->
<echo message="Checking if ${user.input.xml} is well formed"/>
<xmlvalidate file="${user.input.xml}" failonerror="false" lenient="true"/>
<!-- HOW WE COULD CHECK THE RESULT OF THE VALIDATION OPERATIONS
WITHOUT EXITING ?-->
<!-- Checking if file validates against XSD -->
<echo message="Checking if ${user.input.xml} validates against schema"/>
<schemavalidate noNamespaceFile="${xsds.dir}/userInput.xsd"
file="${user.input.xml}" failonerror="false"/>
<!-- HOW WE COULD CHECK THE RESULT OF THE VALIDATION OPERATIONS
WITHOUT EXITING? -->
<!-- HERE WE SHOULD GET IN A PROPERTY THE STATUS OF THE OPERATION AND WRITE
IN A FILE SOMETHING LIKE : "OPERATION STATUS: SUCCESS/FAILURE: The reason
was: something from the schemavalidate output" -->
<!-- IF THE OPERATION WAS SUCCESSFUL WE SHOULD CALL SOME TASKS OTHERWISE
CALL OTHER TASKS -->
</target>
Thanks in advance for your suggestions.

What I needed actually was the trycatch from antcontrib. This solved my problem as in the snippet below.
<target name="validate-xml-file">
<echo message="Validating ${user.input.xml}"/>
<!-- Checking if XML is well formed -->
<echo message="Checking if ${user.input.xml} is well formed"/>
<trycatch property="xml.well.formed.result">
<try>
<xmlvalidate file="${user.input.xml}" failonerror="true" lenient="true"/>
</try>
<catch/>
<finally/>
</trycatch>
<!-- Checking if file validates against XSD -->
<echo message="Checking if ${user.input.xml} validates against schema"/>
<trycatch property="schema.validation.result">
<try>
<schemavalidate noNamespaceFile="${xsds.dir}/userInput.xsd"
file="${user.input.xml}" failonerror="true"/>
</try>
<catch/>
<finally/>
</trycatch>
<!-- Create two properties for the results of the validation -->
<condition property="xml.well.formed.result.set" else="false">
<isset property="xml.well.formed.result"/>
</condition>
<condition property="schema.validation.result.set" else="false">
<isset property="schema.validation.result"/>
</condition>
<!-- Here we can write into a HTML format the result of the operation according
to the xml.well.formed.result, schema.validation.result a.s.o.) -->
<!-- Also, perform something according to the validation or not of the XML -->
<if>
<or>
<equals arg1="${xml.well.formed.result.set}" arg2="true"/>
<equals arg1="${schema.validation.result.set}" arg2="true"/>
</or>
<then>
<!-- Here we call some task -->
</then>
<else>
<!-- Here we call some other task or just fail to fw the failure -->
</else>
</if>

Why don't you simplify the solution by using filesets (instead of using the 3rd party ant-contrib "foreach" task).
<xmlvalidate failonerror="false" ..>
<fileset dir="${user.folder}" includes="*.xml"/>
</xmlvalidate>
<schemavalidate failonerror="false" ..>
<fileset dir="${user.folder}" includes="*.xml"/>
</schemavalidate>
I just tested a similar solution and got the following message telling me the file and line throwing the validation issues:
[schemavalidate] /path/to/file/file.xml:119:18: cvc-complex-type.2.4.a: Invalid content was found starting with element 'helloworld'. One of '???' is expected.

Related

Ant: If property contains certain string, change the name of the property

I am trying to check a folder's name, and if it contains a certain string, I want that folder path to be changed.
So far I came up with this:
<property name="component.release.dir" value="${install.dir}/${component.name}" />
<!-- Check if the component is a part of projectL -->
<condition property="projectLFolderSpotted">
<matches pattern="projectL" string="${component.release.dir}"/>
<!-- if so, put the component in an appropriate folder -->
<property name="component.release.dir" value="${install.dir}/projectL/${component.name}" />
<echo message="projectL component has been detected, and moved accordingly!"/>
</condition>
But I get the following error:
condition doesn't support the nested "property" element.
Is there a way to achieve this?
Thanks in advance.
Properties in ANT are immutable, once they're assigned a value it doesn't change.
Here's how I'd suggest you do it:
<project name="demo" default="build">
<property name="release.dir.seed" location="build/helloworld"/>
<condition property="release.dir" value="build/found/helloworld" else="build/notfound/helloworld">
<contains string="${release.dir.seed}" substring="helloworld"/>
</condition>
<target name="build">
<echo message="Result: ${release.dir}"/>
</target>
</project>

Ant - String contains within an array of String

I am basically trying to do the following thing in Ant (v1.9.4):
I have a list of fixed string like {a,b,c,d} --> First how should I declare this in Ant?
Then I have an input parameter such as ${mystring} and I want to check if the variable value is in my list. Which means in this example, if the variable value is equals to a or b or c or d.
If so return true else false (or 0 and 1 something like that).
Is there a simple way to do that?
Thanks,
Thiago
Use ant property task to declare your stringlist.
Use ant contains condition to check whether list contains a specific item.
Something like :
<project>
<!-- your stringlist -->
<property name="csvprop" value="foo,bar,foobar"/>
<!-- fail if 'foobaz' is missing -->
<fail message="foobaz not in List => [${csvprop}]">
<condition>
<not>
<contains string="${csvprop}" substring="foobaz"/>
</not>
</condition>
</fail>
</project>
Or wrap it in a macrodef for resuse :
<project>
<!-- your stringlist -->
<property name="csvprop" value="foo,bar,foobar"/>
<!-- create macrodef -->
<macrodef name="listcontains">
<attribute name="list"/>
<attribute name="item"/>
<sequential>
<fail message="#{item} not in List => [#{list}]">
<condition>
<not>
<contains string="${csvprop}" substring="foobaz"/>
</not>
</condition>
</fail>
</sequential>
</macrodef>
<!-- use macrodef -->
<listcontains item="foobaz" list="${csvprop}"/>
</project>
-- EDIT --
From ant manual condition :
If the condition holds true, the property value is set to true by default; otherwise, the property is not set. You can set the value to something other than the default by specifying the value attribute.
So simply use a condition to create a property that is either true or not set, f.e. combined with the new if/unless feature introduced with Ant 1.9.1 :
<project
xmlns:if="ant:if"
xmlns:unless="ant:unless"
>
<!-- your stringlist -->
<property name="csvprop" value="foo,bar,foobar"/>
<!-- create macrodef -->
<macrodef name="listcontains">
<attribute name="list"/>
<attribute name="item"/>
<sequential>
<condition property="itemfound">
<contains string="${csvprop}" substring="foobaz"/>
</condition>
<!-- echo as example only instead of
your real stuff -->
<echo if:true="${itemfound}">Item #{item} found => OK !!</echo>
<echo unless:true="${itemfound}">Warning => Item #{item} not found !!</echo>
</sequential>
</macrodef>
<!-- use macrodef -->
<listcontains item="foobaz" list="${csvprop}"/>
</project>
output :
[echo] Warning => Item foobaz not found !!
Note that you need the namespace declarations to activate the if/unless feature.

In Ant, how can I test if a property ends with a given value?

In Ant, how can I test if a property ends with a given value?
For example
<property name="destdir"
value="D:\FeiLong Soft\Essential\Development\repository\org\springframework\spring-beans" />
how can I test if ${destdir} ends with "spring-beans"?
additional:
In my ant-contrib-1.0b3.jar, without 'endswith' task~~
You can test if ${destdir} ends with "spring-beans" like this (assuming you have ant-contrib, and are using Ant 1.7 or later).
<property name="destdir" value="something\spring-beans" />
<condition property="destDirHasBeans">
<matches pattern=".*spring-beans$" string="${destdir}" />
</condition>
<if>
<equals arg1="destDirHasBeans" arg2="true" />
<then>
$destdir ends with spring-beans ...
</then>
<else> ...
</else>
</if>
The '$' in the regex pattern ".*spring-beans$" is an anchor to match at the end of the string.
As Matteo, Ant-Contrib contains a lot of nice stuff, and I use it heavily.
However, in this case can simply use the <basename> task:
<basename property="basedir.name" file="${destdir}"/>
<condition property="ends.with.spring-beans">
<equals arg1="spring-beans" arg2="${basedir.name}"/>
<condition>
The property ${ends.with.spring-beans} will contain true if ${destdir} ends with string-beans and false otherwise. You could use it in the if or unless parameter of the <target> task.
You can use the EndWith condition from Ant-Contrib
<endswith string="${destdir}" with="spring-beans"/>
For example
<if>
<endswith string="${destdir}" with="spring-beans"/>
<then>
<!-- do something -->
</then>
</if>
Edit
<endswith> is part of the Ant-Contrib package that has to be installed and enabled with
<taskdef resource="net/sf/antcontrib/antlib.xml"/>
The JavaScript power can be used for string manipulation in the ANT:
<script language="javascript"> <![CDATA[
// getting the value for property sshexec.outputproperty1
str = project.getProperty("sshexec.outputproperty1");
// get the tail , after the separator ":"
str = str.substring(str.indexOf(":")+1,str.length() ).trim();
// store the result in a new property
project.setProperty("res",str);
]]> </script>
<echo message="Responce ${res}" />

In the same sql task of ant, is it possible to provide different transaction behaviors for different transactions?

<target name="create-db-tables" depends="initialize">
<fail message="Missing property [datasource.url]." unless="datasource.url" />
<fail message="Missing property [db.user]." unless="db.user" />
<fail message="Missing property [db.password]." unless="db.password" />
<fail message="Missing property [db.sql.driver]." unless="db.sql.driver" />
<sql driver="${db.sql.driver}" url="${datasource.url}" userid="${db.user}" password="${db.password}" output="${basedir}/createTable.log" onerror="continue">
<classpath>
<pathelement location="${basedir}/../lib/ojdbc.jar"/>
</classpath>
<transaction src="${basedir}/ddl/dropTables.sql" />
<transaction src="${basedir}/ddl/createTables.sql" />
</sql>
</target>
I have above target defined in my ant script, which drops the tables first and then creates them. I want ant to ignore the errors when dropping the tables (i.e. onerror="continue"), but to throw exception (i.e. onerror="abort") on error occurred during table creation. But it takes the transaction behavior in the "sql" tag and hence it is common for all the transactions.
I don't want to create separate sql tags and repeat the DB details. Also, I want to execute sql through files. How can I do it through ant?
I would simply do it like this:
create an sql tag for each segment you need, just reuse the properties you giv (this may look ugly and duplicated but works)
define the classpath prior to the sql tag and reuse it via classpathref
It could look like this:
<target name="create-db-tables" depends="initialize">
<fail message="Missing property [datasource.url]." unless="datasource.url" />
<fail message="Missing property [db.user]." unless="db.user" />
<fail message="Missing property [db.password]." unless="db.password" />
<fail message="Missing property [db.sql.driver]." unless="db.sql.driver" />
<classpath id="ojdbcpath">
<pathelement location="${basedir}/../lib/ojdbc.jar"/>
</classpath>
<!--- First Drop -->
<sql driver="${db.sql.driver}" url="${datasource.url}"
userid="${db.user}" password="${db.password}"
output="${basedir}/createTable.log" onerror="continue"
classpathref="ojdbcpath">
<transaction src="${basedir}/ddl/dropTables.sql" />
</sql>
<!--- Then create -->
<sql driver="${db.sql.driver}" url="${datasource.url}"
userid="${db.user}" password="${db.password}"
output="${basedir}/createTable.log" onerror="abort"
classpathref="ojdbcpath">
<transaction src="${basedir}/ddl/createTables.sql" />
</sql>
</target>

Ant Control Flow Break

Is there anything in Ant that allows me to halt the execution of an iterative segment like the break operation? Usage of external libraries is not a problem.
As an example of what I am trying to accomplish:
<for list="1,2,3" param="iteration">
<sequential>
<if>
<equals arg1="#{iteration}" arg2="3"/>
<then>
<!-- Break here -->
</then>
</if>
</sequential>
</for>
The Ant addon Flaka provides a break task, i.e. :
<project xmlns:fl="antlib:it.haefelinger.flaka">
<fl:for var="i" in=" list(1,2,3,4,5,6) ">
<fl:echo>i = #{i}</fl:echo>
<!-- also possible to use
<fl:when test=" i eq 3 "> -->
<fl:when test=" i == 3 ">
<fl:break />
</fl:when>
</fl:for>
</project>
see Flaka Manual especially section 8. Repetative Tasks
for details about break task.

Resources