Scriptlets
Scriptlets perform special Java functions that pull data from a Specify database and translate it into a given format in a report or label. Scriptlets are predefined in the Specify 6 code and provide for a range of possible formatting issues that a collection might come across when making labels and reports. Directions for use and a list of existing scriptlet functions in Specify 6 can be found at Printing With Specify 6's Scriptlet Functions. There are some that are not currently on the list, all of which are explained later in this document.
Note: When using scriptlets in a report, make sure that the Scriptlet Class in Report Properties (Edit>Report Properties) is set to edu.ku.brc.specify.config.Scriptlet (see below).
Also: If copying and pasting, keep in mind that some fields are unique to different schema/databases, so make sure to replace those fields with the correct field in SpiReport.
Scriptlets must be added to the Expression Editor in the following format:
((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).scriptletName(required fields)
The following examples are common use-case scenarios or further explanation for some existing scriptlets:
Expression for formatted Latitude/Longitude and direction characters:
To display latitude and longitude in the original format (as they are shown in Specify) and with direction characters (N, E, S, W), you would use the .formatLatLon and .getDirChar Scriptlets. The query fields necessary for these two scriptlets are latitude1, longitude1, and original latitude longitude unit.
((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).formatLatLon($F{Latitude1}, $F{Original_Latitude_Longitude_Unit}, true) + ((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).getDirChar($F{Latitude1}, true) + " " + ((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).formatLatLon($F{Longitude1}, $F{Original_Latitude_Longitude_Unit}, false) + ((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).getDirChar($F{Longitude1}, false)
The above expression displays as:
More Lat/Long Formatting
Truncating lat/long values
($F{Latitude1}==null?"":((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).formatBigDecimal($F{Latitude1},5)+" ")+($F{Longitude1}==null?"":((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).formatBigDecimal($F{Longitude1}, 5))
To truncate lat/long and get direction characters
($F{Latitude1}==null?"":((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).formatBigDecimal($F{Latitude1},4)+" "+((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).getDirChar($F{Latitude1}, true))
($F{Longitude1}==null?"":((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).formatBigDecimal($F{Longitude1},4)+" "+((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).getDirChar($F{Longitude1}, false))
Note: If you want the lat/long values to print exactly as they are in Specify (ex: decimal degrees), use the lat1text and long1text fields in the Query. This is easier than using the original lat/long scriptlet above, but it doesnât include a directional character.
To set Latitude and Longitude to appear blank when the value is null, follow these steps:
- In the left panel of iReport, right-click Variables and select âAddâŚâ and choose Variable.
- In the Variable form, use these settings:
- The name should be either âLatitudeâ or âLongitude.â Each needs its own variable.
- Variable Class Type - String
- Calculation Type - Nothing
- Reset Type - Report
- Increment Type - None
- Set the Variable Expression to one of these two, depending on whether the variable is Latitude or Longitude:
- ((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).formatLatLon($F{Latitude1}, $F{Original_Latitude_Longitude_Unit}, true) + ((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).getDirChar($F{Latitude1}, true)
- ((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).formatLatLon($F{Longitude1}, $F{Original_Latitude_Longitude_Unit}, false) + ((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).getDirChar($F{Longitude1}, false)
- The Initial Value Expression should be ââ
- In the field where you want the latitude and longitude, the expression will look like this:
($V{Latitude}==null?"":$V{Latitude})+($V{Longitude}==null?"":", "+$V{Longitude})
Remember to edit the fieldâs properties and ensure that the Text Field Expression Class is set to String, or you will get an error when you run the report. There are screen shots of creating a Variable in the next section of this document, if you run into trouble setting up the Lat/Long variables.
Scriptlet for mixed concatenation expressions using ampersands:
((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).escapeForHtml($F{Author})
"<style isItalic=\"true\" pdfFontName=\"Helvetica-Bold\">" + ($F{Genus}==null?"":((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).escapeForHtml($F{Genus}))
+ " " + ($F{Species}==null?"":((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).escapeForHtml($F{Species}))
+ "</style>" +
($F{Species_Author}==null?"":((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).escapeForHtml($F{Species_Author}))
+ " " +
($F{Variety}==null?"":" var. "+"<style isItalic=\"true\" pdfFontName=\"Helvetica-Bold\">" + $F{Variety}+"</style>") + ($F{Variety_Author}==null?"":$F{Variety_Author})
+ " " +
($F{Subspecies}==null?"":" subsp. " + "<style isItalic=\"true\" pdfFontName=\"Helvetica-Bold\">" + $F{Subspecies}+"</style>") + ($F{Subspecies_Author}==null?"":$F{Subspecies_Author})
Better scriptlet for primary collector (this works for both Sp6 and Sp7):
((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).deaggregateFirst($F{Collectors}, â, â) *where $F{Collectors} is the aggregated Collectors field and â, â is the separator
Better scriptlet for secondary collectors (this works for both Sp6 and Sp7):
((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).deaggregateSecondary($F{Collectors}, â, â)
*where $F{Collectors} is the aggregated Collectors field and â, â is the separator
Scriptlet for primary collector (only works for Sp6):
((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).getFirstCollector($F{Catalog_Number})
Scriptlet for secondary collectors (only works for Sp6):
((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).getSecondaryCollectors($F{Catalog_Number})
Scriptlet for calculating length of loan:
((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).dateStringDifference($F{LoanDate}, $F{CurrentDueDate})
To retrieve agents by Loan Agent Role, use the following scriptlet:
((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).getByLoanAgentRole($F{LoanNumber},âagent roleâ,âagent.fieldâ)
âagent roleâ is the role of the agent in the Loan that you are using. For example, if you are using the scriptlet for the agent who is the recipient of the loan, the role will probably be Borrower. Be sure to compare the loan record with the report to make sure you are using the correct role.
âagentâ refers to the table in which the field in question is located. For address fields, the table would be âaddress,â not âagent.â Make sure that the field names match the ones in the schema EXACTLY. To check this, go to Schema Configuration, select the agent or address table (depending on which field you are checking) and look at the Fields box (below the Tables box) to find the name of the field. Some examples of fields you might use are agent.firstName, agent.lastName, address.address, address.city, and address.state. Be sure to compare the loan record with the report to make sure you are using the correct fields.
Examples:
((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).getByLoanAgentRole($F{LoanNumber},âBorrowerâ,âagent.lastnameâ)
((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).getByLoanAgentRole($F{LoanNumber},âBorrowerâ,âloanagent.remarksâ) ***only field where you must type âloanagentâ
((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).getByLoanAgentRole($F{LoanNumber},âBorrowerâ,âaddress.address2â)
*Note: if you use this scriptlet, you do not need to include the Loan Agent fields it calls for in the query. Also, this scriptlet only works for agents added to a Loan record under Loan Agents. It will not work for agents in Shipped To or Shipped By.
Cheap expression: (tip- watch Meredithâs video on Loan Agent Borrower variables:
("".equals($V{BD})?"":$V{BD}+"\n")+("".equals($V{BRB})?"":$V{BRB}+"\n")+("".equals($V{BI})?"":$V{BI}+"\n")+("".equals($V{BA})?"":$V{BA}+"\n")+("".equals($V{BA2})?"":$V{BA2}+"\n")+("".equals($V{BC})?"":$V{BC}+", ")+("".equals($V{BS})?"":$V{BS}+" ")+("".equals($V{BP})?"":$V{BP}+"\n")+($V{BCountry}==null?"":$V{BCountry})
To retrieve agents by Gift Agent Role and Borrow Agent Role, use the following scriptlet:
((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).getByRole("gift","GiftNumber",$F{Gift_Number},"giftagent","Receiver","agent.FirstName")+((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).getByRole("gift","GiftNumber",$F{Gift_Number},"giftagent","Receiver","agent.LastName")
Where âGiftNumberâ is the name of the invoice field in the schema, and $F{Gift_Number} is the fieldâs name in the database/query.
((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).getByRole("borrow","InvoiceNumber",$F{Invoice_Number},"borrowagent","Borrower","agent.FirstName")+((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).getByRole("borrow","InvoiceNumber",$F{Invoice_Number},"borrowagent","Borrower","agent.LastName")
Where âInvoiceNumberâ is the name of the invoice field in the schema, and $F{Invoice_Number} is the fieldâs name in the database/query.
NOTE: This scriptlet also works for exchanges, accessions, etc.
To format Preparations to match the format on the default invoice:
($F{Quantity}==null?"":$F{Quantity}+"").toString() + " " + ($F{Prep_Type}==null?"":$F{Prep_Type}+"") + " of " + ((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).calcLoanQuantity($F{Count}, $F{Quantity_Returned}, $F{Quantity_Resolved}) + " " + ($F{Prep_Type}==null?"":$F{Prep_Type}+"")
This will print preparations in this format (under Specimen Count):
Scriptlet for summarizing Preparations and combining like-PrepTypes:
((edu.ku.brc.specify.config.Scriptlet)$P{REPORT_SCRIPTLET}).aggregatePreps($F{RecordID},"%s - %d", "; ")
Using .replace to Modify Values
The most common uses of modifiers for replacing values are for the Sex pick list and dates (loan date, collected date, cataloged date, etc.) Here are a few example scenarios:
-
A user wants sex pick list values of âMâ, âFâ, and âUNâ from the database to display as âMaleâ, âFemaleâ, and âUnknownâ on the labels. The expression would appear as such:
$F{Sex}.equals("M") ? "Male" : $F{Sex}.equals("F") ? "Female" : $F{Sex}.equals("UN") ? "Sex Unknown" : ""
-
A user is using a sex info field in Specify that can contain multiple values, such as âFâ, âFemaleâ, âMâ, âMaleâ, and perhaps other data. Example of data in Specify:
-
The user wants to use a symbol for the sex instead of text, with any other data in field displaying after. So the expression must account for the multiple sex values:
($F{Sex_(info)}==null ? "": $F{Sex_(info)}.replace("Female","â").replace("F", "â").replace("Male", "â").replace("M","â"))
On the label, the data will display as:
Making US states display abbreviations instead of full names
Making dates display full month names instead of numbers
- Dates are saved in the database in the format â08/22/1994,â but the desired format is â22/August/1994.â The expression would then look like this:
($F{Collection_Date_(Day)}==null?"":$F{Collection_Date_(Day)}+" ").toString()+($F{Collection_Date_(Month)}==null?"":$F{Collection_Date_(Month)}+" ").toString().replace("10","October").replace("11","November").replace("12","December").replace("1","January").replace("2","February").replace("3","March").replace("4","April").replace("5","May").replace("6","June").replace("7","July").replace("8","August").replace("9","September") +($F{Collection_Date_(Year)}==null?"":$F{Collection_Date_(Year)}+"").toString()
Making dates display 3 letter month names instead of numbers, â/â in between
- Dates are saved in the database in the format â08/22/1994,â but the desired format is â22/Aug/1994.â The expression would then look like this:
($F{Loan_Date_(Day)}==null?"":$F{Loan_Date_(Day)}+"/").toString()+($F{Loan_Date_(Month)}==null?"":$F{Loan_Date_(Month)}+"/").toString().replace("10","Oct").replace("11","Nov").replace("12","Dec").replace("1","Jan").replace("2","Feb").replace("3","Mar").replace("4","Apr").replace("5","May").replace("6","Jun").replace("7","Jul").replace("8","Aug").replace("9","Sep") +($F{Loan_Date_(Year)}==null?"":$F{Loan_Date_(Year)}+"").toString()
Making dates have extra zeros
For example, your date looks like this 2012/7/9 and you want it to look like 2012/07/09. Note that the format is year/month/day here, you can switch it around as you wish. Use this expression:
"Date: " + ($F{Date_(Year)}==null?"":$F{Date_(Year)}+"").toString() +($F{Date_(Month)}==null?"":"/"+(($F{Date_(Month)}+"").toString().length() == 2 ? ($F{Date_(Month)}+"").toString(): "0" + $F{Date_(Month)}+"")).toString() + ($F{Date_(Day)}==null?"":"/" + (($F{Date_(Day)}+"").toString().length() == 2 ? ($F{Date_(Day)}+"").toString(): "0" + $F{Date_(Day)}+"")).toString()
- Below is an example of how the order of the date fields can be moved around:
"Det. Date: "+($F{Determined_Date_(Day)}==null?"":$F{Determined_Date_(Day)}+"-").toString()+($F{Determined_Date_(Month)}==null?"":$F{Determined_Date_(Month)}+"-").toString()+($F{Determined_Date_(Year)}==null?"":$F{Determined_Date_(Year)}+"").toString()
To get rid of leading zeros in a catalog number, change 0000123 to 123:
.replaceFirst(" 0+", " ")
To add leading zeros for numeric catalog number format:
("000000000".substring(0,9-$F{CatNo}.toString().length())+$F{CatNo}+"").toString()
*you will probably have to change the field (CatNo) to match whatever is in the database, and the number (9) as well if your catalog number format has less than 9 character length
Get rid of all extra commas or other extra characters/punctuation, use one of these two:
.replaceAll("^, ","")
.trim().replaceAll(",$","").trim().replaceAll(",$","")
*If you want to get rid of other extra characters, replace the comma in the expression above with that character.
Specify 6 vs. Specify 7 â Label/Report Differences
Creating a label:
Currently, Specify 7 does not use any sort of label/report design interface, while Specify 6 uses SpiReport. Because of this, labels must be initially designed and further modified in Specify 6, and then updated in Sp7. This can be done for databases that are being hosted, by either sending Ben the updated label file, sending him the labelâs xml coding (can be found by unzipping label file and copying/pasting from within the data.xml), or by copying/pasting the labelâs xml directly into the Sp7 database (you must have some way of accessing it, if we are hosting then just ask Ben for SpAdmin user/pass). For databases which we are not hosting, you must have the user do the last method mentioned (you may need to guide them through this). Note: the label can be found in Sp7 by clicking on User â Resources â App Resources â Discipline the label is under â label name. When you click on the label, itâs xml will appear to on the screen. Alternatively, if there is an SSH portal linking Sp6 and Sp7 for the database, you can update the label in Sp6 while using the portal, and it will automatically be updated in Sp7. If you have questions about SSH Portals, ask Theresa.
Importing/Exporting a label:
In Specify 6, you can use the Resource Import/Export feature to both import and export labels into/out of the database. There is no way to import/export labels in Specify 7, however you can modify labels by updating the xml, as described above.
Images:
In Specify 6, there are several methods for linking images to reports. In Specify 7, the process has been simplified by means of an images server. For collections which we are hosting on Sp7, you will first add the image in SpiReport, then link it locally to the report logo/image. When you run the report in Sp7, you will be prompted to create a link between the local image file that the report is calling and the images server. Select the local file, and a copy will be created on the image server. After this is done, the image will generate on the report from any machine.
Scriptlets:
The following scriptlets do not work in 7:
- aggregatePrepCounts
- aggregatePreps
- aggregatePreps
- buildLocalityString
- buildNameString
- degrees
- format
- formatDate
- formatDate
- formatDetermination
- formatFieldNo
- formatTaxonWithAuthors
- getAggregated
- getByLoanAgentRole
- getByRole
- getCollectors
- getCollectorsByCOIdNumWithAggregator
- getCollectorsWithAggregator
- getCurrentDate
- getCurrentDeterminationFullName
- getFirstCollector
- getSecondaryCollectors
- getTaxonNameWithAuthors
- getTypeStatus
- getTypeTaxon
- loanCategory
- locality
- localityBD
- sumPrepCounts
- toProperCase