I'm defining a macrodef in Ant, and using javascript to do the work. In this case I'm validating a timezone.
<macrodef name="validateTimeZone">
<attribute name="zone" />
<sequential>
<echo>result: ${envTZResult}</echo>
<echo> validating timezone: #{zone}</echo>
<script language="javascript"><![CDATA[
importClass(java.util.TimeZone);
importClass(java.util.Arrays);
var tz = project.getProperty("zone");
println(" got attribute: " + tz);
var result = Arrays.asList(TimeZone.getAvailableIDs()).contains(tz); //testing if timezone is known
project.setProperty("zoneIsValid", result);
]]>
</script>
</sequential>
</macrodef>
The problem is project.getProperty() doesn't retrieve values of passed attributes. Does somebody know how you could get the value of the attribute from within the javascript?
Turns out I was using the wrong type of tag. For using scripting to define an ant task, I should have used scriptdef and not macrodef. With scriptdef there are predefined objects to access the attributes and nested elements in your task.
This works for accessing attributes from javascript in Ant:
<scriptdef name="validateTimeZone" language="javascript">
<attribute name="zone" />
<![CDATA[
importClass(java.util.TimeZone);
importClass(java.util.Arrays);
var tz = attributes.get("zone"); //get attribute defined for scriptdef
println(" got attribute: " + tz);
var result = Arrays.asList(TimeZone.getAvailableIDs()).contains(tz); //testing if timezone is known
project.setProperty("zoneIsValid", result);
]]>
</scriptdef>
Best is to create a property with attribute as value, i.e.
<macrodef name="validateTimeZone">
<attribute name="zone" />
<sequential>
<echo>result: ${envTZResult}</echo>
<echo> validating timezone: #{zone}</echo>
<!-- edit use local with ant 1.8.x -->
<local name="zone"/>
<property name="zone" value="#{zone}"/>
<script language="javascript"><![CDATA[
importClass(java.util.TimeZone);
importClass(java.util.Arrays);
var tz = project.getProperty("zone");
println(" got attribute: " + tz);
var result = Arrays.asList(TimeZone.getAvailableIDs()).contains(tz); //testing if timezone is known
project.setProperty("zoneIsValid", result);
]]>
</script>
</sequential>
</macrodef>
Related
How can i pass two values in a query string using LzBrowser.loadURL() in openlaszlo.
My sample code:
LzBrowser.loadURL("../modules/Index.jsp?base="+ canvas.base +" id=" + canvas.Id,"fraMain");
I am getting number Format exception:
java.lang.NumberFormatException: For input string: "1 base=1"]
Please help in solving this.
Thanks,
Raj
You should add & between two query parameters . You should write like this
LzBrowser.loadURL("../modules/Index.jsp?base="+ canvas.base +"&id=" + canvas.Id,"fraMain");
We have to provide & amp; instead of &. It worked for me.
The number format exception means, that at some point in your code the browser tries to parse a string into a number. Which version of OpenLaszlo did you use, and which runtime?
Based on the use of LzBrowser (starting with OpenLaszlo 4.1 you have to use lz.Browser instead) it seems that you are using either a 3.x or the 4.0 release of OpenLaszlo.
If you want to use the ampersand "&" within methods containing JavaScript code, the XML entity rules apply (everything which starts with an & will be treated as an XML entitity). Adding sections in your methods will let you use the & as you'd do in normal JavaScript or ActionScript code, e.g.
<canvas debug="true">
<button text="Open URL" onclick="canvas.loadUrl()" />
<attribute name="base" type="number" value="99" />
<attribute name="iD" type="number" value="10" />
<method name="loadUrl"><![CDATA[
lz.Browser.loadURL("http://www.google.com?base=" + canvas.base + "&iD=" + canvas.iD, "_blank");
]]></method>
</canvas>
Without the CDATA section, the following compiler error will be thrown:
loadurl.lzx:10:71: The reference to entity "iD" must end with the ';'
delimiter. Look for a misplaced or unescaped ampersand ('&') character
in your source code.
The described workaround of using "&" instead of "&" and no CDATA section is of course a valid option - although it reduced the readability of the JavaScript code in my eyes.
Actually there are two ways to do this, both of the following are correct:
1) Escape the special HTML characters (in this case &) by surrounding the internal code with <![CDATA[ and ]]> tags:
<method name="loadUrl">
<![CDATA[
lz.Browser.loadURL("http://www.google.com?base=" + canvas.base + "&iD=" + canvas.iD, "_blank");
]]>
</method>
2) HTML-entity encode the & character to &
<method name="loadUrl">
lz.Browser.loadURL("http://www.google.com?base=" + canvas.base + "&iD=" + canvas.iD, "_blank");
</method>
Which method you choose is up to your own preference.
HI, I am using Xalan to parse my xsl file. The xsl is working properly in the vb.net parsers. But Xalan gives error for that xsl.
For extension function, could not find
method
java.lang.String.FctDateDuration([ExpressionContext,]
STRING).
Here is how I have define my xsl.
xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:ttVB="ttVB" exclude-result
Here is the java script calling part in xsl : -
<xsl:variable name="start">
xsl:value-of select="substring(DepartureDateTime,1,10)" />
</xsl:variable>
xsl:variable name="end">
xsl:value-of select="substring(following-sibling::OriginDestinationInformation/DepartureDateTime,1,10)" />
</xsl:variable>
xsl:variable name="end1">
xsl:value-of select="substring(preceding-sibling::OriginDestinationInformation/DepartureDateTime,1,10)" />
</xsl:variable>
xsl:variable name="dd" select="ttVB:FctDateDuration(string('2011-02-20'),string('2011-02-25'))"/>
xsl:variable name="dd1" select="ttVB:FctDateDuration(string('2011-02-20'),string('2011-02-25'))"/>
<xsl:choose>
xsl:when test="$dd = 0 or $dd = 1">
<timeQualifier>TA</timeQualifier>
</xsl:when>
xsl:otherwise>
timeQualifier>TD</timeQualifier>
</xsl:otherwise>
</xsl:choose>
Here is my Javascript
<msxsl:script language="JavaScript" implements-prefix="ttVB">
<![CDATA[
function FctDateDuration(p_startDate,p_endDate){
if (IsDate(p_startDate) && IsDate(p_endDate)){
FctDateDuration = String(calcDays(p_startDate, p_endDate))
}else{
FctDateDuration = p_startDate + p_endDate
}
return FctDateDuration;
}
function IsDate(ddate){
//alert("Inside IsDate >> "+ddate);
var dteDate;
var year = ddate.substring(0, 4);
var month = ddate.substring(5, 7);
var day = ddate.substring(8,10);
month = month-1;
//alert(year);
//alert(month);
//alert(day);
dteDate=new Date(year,month,day);
return ((day==dteDate.getDate()) && (month==dteDate.getMonth()) && (year==dteDate.getFullYear()));
}
function calcDays(date1,date2){
date1 = date1.split("-");
date2 = date2.split("-");
var sDate = new Date(date1[0]+"/"+date1[1]+"/"+date1[2]);
var eDate = new Date(date2[0]+"/"+date2[1]+"/"+date2[2]);
var daysApart = Math.abs(Math.round((sDate-eDate)/86400000));
//document.getElementById('diffDays').lastChild.data = daysApart;
//alert(daysApart);
return daysApart;
}
]]>
</msxsl:script>
Well extension functions are hardly portable, not even the way they are defined is portable. With .NET you can use the msxsl:script element to define extension functions but don't expect Xalan to support that. According to http://xml.apache.org/xalan-j/extensions.html#ex-basic Xalan Java supports a xalan:script element if you put bsf.jar and js.jar on the classpath.
You should mark the java script section as CDATA.
See below
<xalan:component prefix="ttVB" functions="FctDateDuration">
<xalan:script lang="javascript">
<![CDATA[
function FctDateDuration(p_startDate,p_endDate){
//alert("inside");
.
.
}]]>
</xalan:script>
I was able to parse the xsl properly. Thanks Martin for the help you gave.
I would like to put here the changes I made. So It'll help to others.
I had to use bsf.jar and js.jar. Since bsf jar is not shipped with xalan. bsf-2.4.0
Also I would like to tell that I had to use the xalan jars separately. Java 1.5 inbuilt xalan gave me errors.
I changed the xsl decleration
sl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xalan="http://xml.apache.org/xalan" xmlns:ttVB="ext1" extension-element-prefixes="ttVB" exclude-result-prefixes="ttVB" version="1.0"
And Javascript declaration according to the http://xml.apache.org/xalan-j/extensions.html#ex-basic
xalan:component prefix="ttVB" functions="FctDateDuration">
xalan:script lang="javascript">
Does Ant have any way of doing string uppercase/lowercase/captialize/uncaptialize string manipulations? I looked at PropertyRegex but I don't believe the last two are possible with that. Is that anything else?
From this thread, use an Ant <script> task:
<target name="capitalize">
<property name="foo" value="This is a normal line that doesn't say much"/>
<!-- Using Javascript functions to convert the string -->
<script language="javascript"> <![CDATA[
// getting the value
sentence = project.getProperty("foo");
// convert to uppercase
lowercaseValue = sentence.toLowerCase();
uppercaseValue = sentence.toUpperCase();
// store the result in a new property
project.setProperty("allLowerCase",lowercaseValue);
project.setProperty("allUpperCase",uppercaseValue);
]]> </script>
<!-- Display the values -->
<echo>allLowerCase=${allLowerCase}</echo>
<echo>allUpperCase=${allUpperCase}</echo>
</target>
Output
D:\ant-1.8.0RC1\bin>ant capitalize
Buildfile: D:\ant-1.8.0RC1\bin\build.xml
capitalize:
[echo] allLowerCase=this is a normal line that doesn't say much
[echo] allUpperCase=THIS IS A NORMAL LINE THAT DOESN'T SAY MUCH
BUILD SUCCESSFUL
Update for WarrenFaith's comment to separate the script into another target and pass a property from the called target back to the calling target
Use antcallback from the ant-contrib jar
<target name="testCallback">
<antcallback target="capitalize" return="allUpperCase">
<param name="param1" value="This is a normal line that doesn't say much"/>
</antcallback>
<echo>a = ${allUpperCase}</echo>
</target>
and capitalise task uses the passed in param1 thus
<target name="capitalize">
<property name="foo" value="${param1}"/>
Final output
[echo] a = THIS IS A NORMAL LINE THAT DOESN'T SAY MUCH
you could use the script task and use a jsr223-supported script language like javascript, jruby, jython,... to do your string handling
I have an XML file of the following form -
<map MAP_XML_VERSION="1.0">
<entry key="database.user" value="user1"/>
...
</map>
Does ant have a native ability to read this and let me perform an xquery to pull back values for keys? Going through the API I did not see such capabilities.
The optional Ant task XMLTask is designed to do this. Give it an XPath expression and you can select the above into (say) a property. Here's an article on how to use it, with examples. It'll do tons of other XML-related manipulations/querying/creation as well.
e.g.
<xmltask source="map.xml">
<!-- copies to a property 'user' -->
<copy path="/map/entry[#key='database.user']/#value" attrValue="true" property="user"/>
</xmltask>
Disclaimer: I'm the author.
You can use the scriptdef tag to create a JavaScript wrapper for your class. Inside JS, you pretty much have the full power of Java and can do any kind of complicated XML parsing you want.
For example:
<project default="build">
<target name="build">
<xpath-query query="//entry[#key='database.user']/#value"
xmlFile="test.xml" addproperty="value"/>
<echo message="Value is ${value}"/>
</target>
<scriptdef name="xpath-query" language="javascript">
<attribute name="query"/>
<attribute name="xmlfile"/>
<attribute name="addproperty"/>
<![CDATA[
importClass(java.io.FileInputStream);
importClass(javax.xml.xpath.XPath);
importClass(javax.xml.xpath.XPathConstants);
importClass(javax.xml.xpath.XPathFactory);
importClass(org.xml.sax.InputSource);
var exp = attributes.get("query");
var filename = attributes.get("xmlfile");
var input = new InputSource(new FileInputStream(filename));
var xpath = XPathFactory.newInstance().newXPath();
var value = xpath.evaluate(exp, input, XPathConstants.STRING);
self.project.setProperty( attributes.get("addproperty"), value );
]]>
</scriptdef>
</project>
Sounds like you want something like ant-xpath-task. I'm not aware of a built-in way to do this with Ant.
I'm currently in the process of replacing my homebrewn build script by an Ant build script.
Now I need to replace various tokens by the size of a specific file. I know how to get the size in bytes via the <length> task and store in in a property, but I need the size in kilobytes and megabytes too.
How can I access the file size in other representations (KB, MB) or compute these values from within the Ant target and store them in a property?
Edit: After I discovered the <script> task, it was fairly easy to calculate the other values using some JavaScript and add a new property to the project using project.setNewProperty("foo", "bar");.
I found a solution that does not require any third-party library or custom tasks using the <script> task that allows for using JavaScript (or any other Apache BSF or JSR 223 supported language) from within an Ant target.
<target name="insert-filesize">
<length file="${afile}" property="fs.length.bytes" />
<script language="javascript">
<![CDATA[
var length_bytes = project.getProperty("fs.length.bytes");
var length_kbytes = Math.round((length_bytes / 1024) * Math.pow(10,2))
/ Math.pow(10,2);
var length_mbytes = Math.round((length_kbytes / 1024) * Math.pow(10,2))
/ Math.pow(10,2);
project.setNewProperty("fs.length.kb", length_kbytes);
project.setNewProperty("fs.length.mb", length_mbytes);
]]>
</script>
<copy todir="${target.dir}">
<fileset dir="${source.dir}">
<include name="**/*" />
<exclude name="**/*.zip" />
</fileset>
<filterset begintoken="$$$$" endtoken="$$$$">
<filter token="SIZEBYTES" value="${fs.length.bytes}"/>
<filter token="SIZEKILOBYTES" value="${fs.length.kb}"/>
<filter token="SIZEMEGABYTES" value="${fs.length.mb}"/>
</filterset>
</copy>
</target>
There is a math task at http://ant-contrib.sourceforge.net/ that may be useful