I have an xml-file - call it myXML.xml - like this:
<?xml version="1.0" encoding="UTF-8"?>
<Metrics info1="1" info2="2" info3="3" xmlns="http://metrics.sourceforge.net/2003/Metrics-First-Flat">
<Metric id = "NORM" description ="Number of Overridden Methods">
<Values per = "type" total = "135" avg = "0.452" stddev = "0.94" max = "5">
<Value name="a" source ="a.java" package ="package.a" value ="1"/>
<Value name="b" source ="b.java" package ="package.b" value ="34"/>
<Value name="c" source ="c.java" package ="package.c" value ="4"/>
<Value name="d" source ="d.java" package ="package.d" value ="99"/>
<Value name="e" source ="e.java" package ="package.e" value ="99"/>
<Value name="f" source ="f.java" package ="package.f" value ="99"/>
<Value name="g" source ="g.java" package ="package.g" value ="99"/>
</Values>
</Metric>
<Metric id = "NOI" description ="Number of Overridden Methods">
<Values per = "type" total = "135" avg = "0.452" stddev = "0.94" max = "5">
<Value name="a" source ="a.java" package ="package.a" value ="10"/>
<Value name="b" source ="b.java" package ="package.b" value ="340"/>
<Value name="c" source ="c.java" package ="package.c" value ="40"/>
<Value name="d" source ="d.java" package ="package.d" value ="990"/>
</Values>
</Metric>
</Metrics>
Because I have to evaluate dozens of such files (like myXML.xml
) over dozens of attributes (here id=NORM
and id=NOI
) I tried to automate this in Apache Ant.
The best case scenario would be to get for a fixed file (myXML.xml
) a csv-file in return - which will be saved as myXML.csv - and looks something like
NORM 1, 34, 4, 99, 99, 99, 99
NOI 10, 340, 40, 990
To approach this, I thought to create a property file <property file="metrics.properties"/>
which looks like
p_1 = NORM
p_2 = NOI
...
p_N = VG
where N
is arbitrary, so Ant has to figure out N
(in the small example here N=2
) and create the csv-file as mentioned above over all p_i's
. Further I guess I should rewrite the below xquery as a function of the file (myXML.xml
) and NORM
and run it from the command line. But I don't see how to do either of this.
The following xquery is partially doing what I am interested in:
declare option db:stripns 'true';
for $x in doc("myXML.xml")/Metrics/Metric[@id="NORM"]/Values//Value/@value
return data($x)
but both myXML.xml
and NORM
are fixed and the output is simply 1 34 4 99 99 99 99 . I saved this file in query.xq
and ran it in Ant:
<target name="ant" depends="#1">
<echo> ant </echo>
<exec executable="${pathToAnt}/basex.bat" dir="${basedir}" error="${basedir}/output/error.txt">
<arg value = "query.xq"/>
<redirector output="${basedir}/output/myXML.csv" alwayslog="true"/>
</exec>
</target>
That's what I have - little far from what I intend to get.
I hope it's clear what I am trying to achieve. I am new to xquery aswell to ant and I am using BaseX (not a must) under Windows, thus this is quite challenging to me ;-).
Thanks a lot for any help, hints, questions, etc.
Thanks for your help. I figured it out:
A for loop can be done using http://ant-contrib.sourceforge.net/tasks/tasks/for.html. I did an iteration over all my source files (their names are stored in fileNames
) which looks like
<for list="${fileNames}" delimiter="," param="nameIter">
<sequential>
<echo> loop over fileNames: nameIter=@{nameIter} </echo>
<exec executable="${pathToAnt}/basex.bat" dir="${basedir}" error="${basedir}/output/error_baseX/@{nameIter}Error.txt">
<arg value="-b$importList=${metricsList}" />
<arg value="-b$name=@{nameIter}"/>
<arg value="./source_data/data/query.xq"/>
<redirector output="${basedir}/output/@{nameIter}.csv" alwayslog="true"/>
</exec>
</sequential>
</for>
Now, the exec-part runs the following xquery from command line, where the variable metricsList
consist of all the metrics I am interested in. In the xml above for instance this would be metricsList=NORM,NOI
. The xquery file query.xq
is
declare option db:stripns 'true';
declare variable $name external;
declare variable $importList external;
declare variable $list as xs:string* := tokenize($importList, ',');
for $i in $list
let $x := doc($name)/Metrics/Metric
let $nl := " " (: this is a newline:)
return ($nl,data($x[@id=$i]/Values/../@id), data($x[@id=$i]/Values/Value/@value))