how to use java in xslt and avoid below errors:
Cannot find a 1-argument function named
{java:com.poc.XSDDateTimeFormatter}toXSD(). Reflexive calls to Java
methods are not available under Saxon-HE and Cannot find a 2-argument
function named
{urn:java:com.poc.NLDataUnitTestTimeCalc}computeTestTime(). Reflexive
calls to Java methods are not available under Saxon-HE
computeTestTime method of NLDataUnitTestTimeCalc class
public static long computeTestTime( String startDateStr, String endDateStr) {
long testTime= 0;
long longStartDate= 0;
long longEndDate= 0;
for( String format: formats) {
try {
SimpleDateFormat formatter = new SimpleDateFormat(format);
Date startdate = formatter.parse(startDateStr);
Date enddate = formatter.parse(endDateStr);
longStartDate=startdate.getTime();
longEndDate=enddate.getTime();
testTime = (Math.abs(longEndDate-longStartDate)/1000);
break;
}
catch (ParseException ex) {
//ignore
}
}
return testTime;
}
toXSD method of XSDDateTimeFormatter class
public static String toXSD( String dateStr) {
for( String format: formats) {
try {
Date date = new SimpleDateFormat( format).parse( dateStr);
String xsd = new SimpleDateFormat( XSDdateTimeFormat).format( date);
//special case for xsd:dateTime timezone format
return
xsd.substring(0, xsd.length() - 2) +
':' +
xsd.substring(xsd.length() - 2);
} catch (ParseException ex) {
//ignore
}
}
return dateStr; }
xslt
<xsl:template match="/Event">
<bus:Timestamp>
<xsl:value-of xmlns:XSDDateTimeFormatter="java:com.amd.pde.integration.XSDDateTimeFormatter"
select="XSDDateTimeFormatter:toXSD( //TimeStamp)"
/>
</bus:Timestamp>
sample xml
<Event>
<Message>BEGINEXECUTION</Message>
<TimeStamp>20080111000419146</TimeStamp>
<EquipmentID>stack</EquipmentID>
</Event>
As the error message says, you use Saxon-HE, but extension functions in Java are only supported by Saxon-PE and Saxon-EE. The Saxon-Docs mention this explicitly.
I guess you have two options
Buy Saxon-PE or Saxon-EE
Implement your functions in XSL
Related
This question already has answers here:
Java 8 DateTimeFormatter parsing for optional fractional seconds of varying significance
(2 answers)
Closed 3 years ago.
String has to be converted to type LocalDateTime - "yyyy-MM-dd'T'HH:mm:ss".
Just ignore anything after seconds.
tried this code but errors out for anything that comes after seconds.
String testDate = "2019-09-17T23:38:47";
LocalDateTime lDate = null;
if (!StringUtils.isEmpty(testDate) && !"".equals(testDate)) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
try {
sqlDate = LocalDateTime.parse(testDate, formatter);
log.info("Converted SQL date=" + lDate );
} catch (Exception ex) {
log.error("Error in parsing lDate " +ex);
}
}
Try this: (+ exception handling)
String testDate = "2019-09-17T23:38:47.342";
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
java.util.Date date = format.parse(testDate);
LocalDateTime localDateTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
System.out.println(localDateTime);
System.out.println(localDateTime.getNano());
Output:
2019-09-17T23:38:47
0
As you can see, the fractional seconds are eliminated.
Edit:
Here's a solution with more recent date-time classes:
DateTimeFormatter format = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd'T'HH:mm:ss")
.appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true)
.toFormatter();
LocalDateTime date1 = LocalDateTime.parse("2019-09-17T23:38:47", format).withNano(0);
LocalDateTime date2 = LocalDateTime.parse("2019-09-17T23:38:47.342", format).withNano(0);
System.out.println(date1);
System.out.println(date2);
Output:
2019-09-17T23:38:47
2019-09-17T23:38:47
Edit 2:
I've constructed an example for how you might deal with different types of inputs using regular expressions and format strings:
InputDatePattern.java
public enum InputDatePattern
{
WITH_TIMESTAMP("\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{0,9})?", Optional.of("yyyy-MM-dd'T'HH:mm:ss")),
WITHOUT_TIMESTAMP("\\d{4}-\\d{2}-\\d{2}", Optional.of("yyyy-MM-dd")),
TIMESTAMP_ONLY("\\d{2}:\\d{2}:\\d{2}(\\.\\d{0,9})?", Optional.of("HH:mm:ss")),
UNKNOWN(".*", Optional.empty()); // must come last, since elements are matched in order
private final Pattern pattern;
private final Optional<DateTimeFormatter> formatter;
private static final LocalDate DEFAULT_DATE = LocalDate.EPOCH;
private static final LocalTime DEFAULT_TIME = LocalTime.MIDNIGHT;
private static final Logger log = Logger.getLogger(Logger.class.getName());
private InputDatePattern(String regex, Optional<String> format)
{
pattern = Pattern.compile(regex);
var formatter = Optional.of(new DateTimeFormatterBuilder());
formatter.ifPresent(f -> format.ifPresent(f::appendPattern));
formatter.ifPresent(f -> f.appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true));
this.formatter = formatter.map(DateTimeFormatterBuilder::toFormatter);
}
public boolean matches(String type)
{
return pattern.matcher(type).matches();
}
public Optional<LocalDateTime> toLocalDateTime(String dateString)
{
try
{
switch(this)
{
case WITH_TIMESTAMP:
return formatter.map(f -> LocalDateTime.parse(dateString, f).withNano(0));
case WITHOUT_TIMESTAMP:
return toLocalDate(dateString).map(date -> date.atTime(DEFAULT_TIME).withNano(0));
case TIMESTAMP_ONLY:
return toLocalTime(dateString).map(date -> date.atDate(DEFAULT_DATE).withNano(0));
case UNKNOWN:
return Optional.empty();
default:
throw new IllegalStateException("Attempting conversion with unknown InputDatePattern!");
}
}
catch(DateTimeParseException e)
{
log.info(e.getMessage());
return Optional.empty();
}
}
public Optional<LocalDate> toLocalDate(String dateString)
{
try
{
switch(this)
{
case WITH_TIMESTAMP:
case WITHOUT_TIMESTAMP:
return formatter.map(f -> LocalDate.parse(dateString, f));
case TIMESTAMP_ONLY:
case UNKNOWN:
return Optional.empty();
default:
throw new IllegalStateException("Attempting conversion with unknown InputDatePattern!");
}
}
catch(DateTimeParseException e)
{
log.info(e.getMessage());
return Optional.empty();
}
}
public Optional<LocalTime> toLocalTime(String dateString)
{
try
{
switch(this)
{
case WITH_TIMESTAMP:
case TIMESTAMP_ONLY:
return formatter.map(f -> LocalTime.parse(dateString, f));
case WITHOUT_TIMESTAMP:
case UNKNOWN:
return Optional.empty();
default:
throw new IllegalStateException("Attempting conversion with unknown InputDatePattern!");
}
}
catch(DateTimeParseException e)
{
log.info(e.getMessage());
return Optional.empty();
}
}
public static InputDatePattern forDateString(String dateString)
{
for(InputDatePattern pattern : InputDatePattern.values())
{
if(pattern.matches(dateString))
return pattern;
}
return InputDatePattern.UNKNOWN;
}
}
Demo.java
public class Demo
{
public static void main(String[] args)
{
String[] trying = {"2019-09-17T23:38:00", "2019-09-17T23:38:00.123",
"2019-09-17", "bad input", "09:12:13.45"};
for(String str : trying)
{
InputDatePattern pattern = InputDatePattern.forDateString(str);
System.out.format("Input pattern type for %s is %s%n", str, pattern);
Optional<LocalDateTime> localDateTime = pattern.toLocalDateTime(str);
if(localDateTime.isPresent())
{
System.out.println("The corresponding LocalDateTime is: "+localDateTime.get());
}
else
{
System.out.format("Unknown type of LocalDateTime! Bad input=\"%s\"%n",str);
}
}
}
}
Output:
Input pattern type for 2019-09-17T23:38:00 is WITH_TIMESTAMP
The corresponding LocalDateTime is: 2019-09-17T23:38
Input pattern type for 2019-09-17T23:38:00.123 is WITH_TIMESTAMP
The corresponding LocalDateTime is: 2019-09-17T23:38
Input pattern type for 2019-09-17 is WITHOUT_TIMESTAMP
The corresponding LocalDateTime is: 2019-09-17T00:00
Input pattern type for bad input is UNKNOWN
Unknown type of LocalDateTime! Bad input="bad input"
Input pattern type for 09:12:13.45 is TIMESTAMP_ONLY
The corresponding LocalDateTime is: 1970-01-01T09:12:13
I have few files in an FTP folder with names like:
mainimport_31052017.csv
mainimport_21052017.csv
mainimport_15052017.csv
And I have a pattern string:
String pattern = "mainimport_ddmmyyy";
Now I am supposed to download the file with the latest date in its title. I am supposed to do it with Java 8 goodies.
I have a solution, but this is not pretty enough, I am doing it in 2 statements:
1) I first get the newest date:
Date newestDate = Collections.max(ftpFiles.stream().filter(fileName -> StringUtils.startsWith(fileName.getName(), prefix)).map(fileName -> {
String fileNameSuffix = fileName.getName().split("_")[1];
Date date = null;
try {
date = dateFormat.parse(fileNameSuffix);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}).collect(Collectors.toList()));
2) I then get the filename with the latest date:
Optional<FTPFile> file = ftpFiles.stream().filter(fileName->{
String fileNameSuffix = fileName.getName().split("_")[1];
Date date = null;
try {
date = dateFormat.parse(fileNameSuffix);
} catch (ParseException e) {
e.printStackTrace();
}
return StringUtils.startsWith(fileName.getName(), prefix) && date.equals(newestDate);
}).findFirst();
I am trying to do this both in a single statement, if it is possible.
Assuming that the dates always have the specified six-character representation, you may use
Optional<FTPFile> max = ftpFiles.stream()
.filter(file -> file.getName().startsWith(prefix))
.max(Comparator.comparing(file -> file.getName()
.replaceFirst(".*_([0-9]{2})([0-9]{2})([0-9]{4}).*", "$3$2$1")));
The factory method Comparator.comparing allows you to create a Comparator based on a property, so that the maximum element will be the element with the maximum value for that property.
Note that this simply converts the ddmmyyyy formatted date to a yyyymmdd string which can be compared lexicographically, which works as long as the day and months always have a two-digit form, i.e. with a leading zero.
You may optimize this a bit by preparing and reusing the regex pattern:
Pattern pattern = Pattern.compile(".*_([0-9]{2})([0-9]{2})([0-9]{4}).*");
Optional<FTPFile> max = ftpFiles.stream()
.filter(file -> file.getName().startsWith(prefix))
.max(Comparator.comparing(file ->
pattern.matcher(file.getName()).replaceFirst("$3$2$1")));
If the DateFormat is an unavoidable prerequisite, you may use
Optional<FTPFile> max = ftpFiles.stream()
.filter(file -> file.getName().startsWith(prefix))
.max(Comparator.comparing(file -> {
String name = file.getName();
name = name.substring(name.indexOf('_')+1);
try {
return dateFormat.parse(name);
} catch (ParseException e) {
throw new IllegalArgumentException(e);
}
}));
This performs the operation in one go, but has the disadvantage of performing the parsing operation more than necessary during the comparisons. If you want to avoid that, you may resort to the original two pass design, but you still don’t need to collect into a List:
ftpFiles.stream()
.map(FTPFile::getName)
.filter(name -> name.startsWith(prefix))
.map(name -> {
name = name.substring(name.indexOf('_')+1);
try {
return dateFormat.parse(name);
} catch (ParseException e) {
throw new IllegalArgumentException(e);
}
})
.max(Comparator.naturalOrder())
.map(date -> prefix+'_'+dateFormat.format(date))
.flatMap(fileName -> ftpFiles.stream()
.filter(file -> file.getName().equals(fileName)).findAny())
.ifPresent(System.out::println);
I have below method in which different date patterns have been handled
below is the method in which different date formats have been handled now
now for the particulat format YYYY-MM-dd i don't want it to go for the check where we are prefixing 20 before in code please advise how can i skip that part lets say if the date pattern is YYYY-MM-dd then avoid the logic of prefixing 20 in front of year
below is my code
public java.util.Date extractDate(String dateStr, String dateType) {
String[] datePatternsOfUk = { "d-M-yy", "d-M-yyyy", "d/M/yy", "d/M/yyyy", "yyyy-MM-dd","dd-MM-yy", "dd-MMM-yy","dd-MMM-yyyy","dd-MM-yyyy",
"dd/MM/yy","dd/MMM/yy","dd/MMM/yyyy"};
String[] datePatternsOfUs = { "M-d-yy","MM-dd-yy","M/d/yy","MM/dd/yy", "MM/dd/yy", "MMM-dd-yy",
"MMM/dd/yy", "MMM-dd-yyyy", "MM-dd-yyyy", "MMM/dd/yyyy",
"MM/dd/yyyy" };
java.util.Date date = null;
String[] datePatterns = datePatternsOfUk;
if (dateType.equals("US")) {
datePatterns = datePatternsOfUs;
} else if (dateType.equals("UK")) {
datePatterns = datePatternsOfUk;
}
///******code should not go in this check where date pattern is YYYY-MM-dd
int p = dateStr.lastIndexOf("/");
if (p == -1) {
p = dateStr.lastIndexOf("-");
}
String firstSubstring = dateStr.substring(0, p + 1);
String secondSubstring = dateStr.substring(p + 1);
if (p != -1 && secondSubstring.length() <= 2) {
secondSubstring = Integer.toString(2000 + Integer.parseInt(secondSubstring));
dateStr = firstSubstring + secondSubstring;
}
///****************************************//
try {
date = DateUtils.parseDate(dateStr, datePatterns);
} catch (ParseException ex) {
logger.error("##$$$$$### Error in invoice inside extractDate method : ##$$$$$$#### "
+ ErrorUtility.getStackTraceForException(ex));
}
return date;
}
You could avoid trying any inappropriate pattern by checking if the string "looks like" the pattern before parsing with the pattern.
The general way to do this is:
String datePattern = "yyyy-MM-dd"; // for example
String input;
if (input.matches(datePattern.replaceAll("\\w", "\\d"))) {
// the input looks like the pattern
// in this example "dddd-dd-dd" where "d" is any digit
// so go ahead and try the parse
}
You can enhance this logic to add:
if (input.matches("\\d\\d\\D.*")) {
// then it only has a two digit year, so add "20" to the front
}
if (!dateStr.equals("YYYY-MM-dd")) {
// code
}
I have to Validate a date in Java to check if it is in correct format and correct value.
If I use SimpleDateformat Class, it will make wrong date valid as well because if a month is given as 14 it will add 1 year to the Year part.
However in Oracle it will indivisually check if Month , Date , Hour , Minute etc is correct.
E.g. in Oracle
TO_DATE(20141511 , 'YYYYMMDD')
will give error that the MONTH i.e. 15 is incorrect
But in Java
Date d = "YYYYMMDD".parse("20141511");
will be valid because it will count it as 2015+3 months.
So, how can I validate a date in Java exactly like Oracle does in its TO_DATE function?
If I understand your question, you could use DateFormat.setLenient(false). Per the JavaDoc,
Specify whether or not date/time parsing is to be lenient ... With strict parsing, inputs must match this object's format.
DateFormat df = new SimpleDateFormat("yyyyMMdd");
df.setLenient(false);
try {
Date d = df.parse("20141511");
} catch (ParseException e) {
e.printStackTrace();
}
Does not allow the invalid date to parse and throws
java.text.ParseException: Unparseable date: "20141511"
None of these solutions account Oracle settings for the date format. A more global solution using oracle.sql.Date and exceptions:
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import oracle.sql.DATE;
public void validateDate (String dateString, String nlsDateFormat, String nlsDateLanguage) throws ParseException, SQLException {
if (dateString == null) {
throw new ParseException("Date parameter not entered.", 0);
} else {
try {
DATE.fromText(dateString, nlsDateFormat, nlsDateLanguage); //not implemented in every ojdbc driver, works with ojbdbc6.jar
} catch (SQLException e) {
if (!e.getMessage().contains("Unimplemented")) {
throw new SQLException (e);
}
}
}
}
(I discovered some drivers couldn't even handle this.. so validation is bypassed if oracle.sql.DATE is not implemented)/ To get session variables for NLS_FORMAT and NLS_LANGUAGE:
private String getDateNlsFmt() throws SQLException {
String nlsDateFormat;
String sqlStmt =
"SELECT value nlsDateFormat "
+ " FROM nls_session_parameters "
+ " WHERE parameter = 'NLS_DATE_FORMAT' ";
QueryStatement q = new QueryStatement(conn, sqlStmt);
q.open();
if (!q.eof()) {
nlsDateFormat = q.getString("nlsDateFormat");
}
q.close();
return nlsDateFormat;
}
private String getDateNlsLang() throws SQLException {
String nlsDateLanguage;
String sqlStmt =
"SELECT value nlsDateLanguage "
+ " FROM nls_session_parameters "
+ " WHERE parameter = 'NLS_DATE_LANGUAGE' ";
QueryStatement q = new QueryStatement(conn, sqlStmt);
q.open();
if (!q.eof()) {
nlsDateLanguage = q.getString("nlsDateLanguage");
}
q.close();
return nlsDateLanguage;
}
I am parsing several documments with the field Duration. But in the differents files, it is in differnt formats, ex:
"Duration": "00:43"
"Duration": "113.046"
"Duration": "21.55 s"
I want to parse all of them to the format "Duration": "113.046", how could I check before any parsing in wich format it is??
Some conditions before this piece of code, because this is not right for all of them:
Long duration;
DateFormat sdf = new SimpleDateFormat("hh:mm:ss");
try {
Date durationD = sdf.parse(totalDuration);
Date zeroSec = sdf.parse("00:00:00");
duration = durationD.getTime() - zeroSec.getTime();
} catch (Exception e) {
duration = Long.parseLong(totalDuration);
}
Thanks in advance
You could match the pattern with help of regex and then format accordingly. Here's a kickoff example:
Map<Pattern, DateFormat> dateFormatPatterns = new HashMap<Pattern, DateFormat>();
dateFormatPatterns.put(Pattern.compile("\\d{1,2}:\\d{2}"), new SimpleDateFormat("H:m"));
dateFormatPatterns.put(Pattern.compile("\\d{1,3}\\.\\d{3}"), new SimpleDateFormat("s.S"));
dateFormatPatterns.put(Pattern.compile("\\d{1,2}\\.\\d{2} s"), new SimpleDateFormat("s.S 's'"));
String[] strings = { "00:43", "113.046", "21.55 s" };
DateFormat finalFormat = new SimpleDateFormat("HH:mm:ss");
for (String string : strings) {
for (Pattern pattern : dateFormatPatterns.keySet()) {
if (pattern.matcher(string).matches()) {
Date date = dateFormatPatterns.get(pattern).parse(string);
String formattedTime = finalFormat.format(date);
System.out.println(formattedTime);
break;
}
}
}
This yields here
00:43:00
00:01:53
00:00:21
If these are all your known input formats, then convert your input to your expected date format.
Just string-replace all : with . and remove s.
Do not forget to strip the spaces, too. By the way, "113.046" seems a bit odd date format to me - if I were in your shoes, I would have used some of the standard date time formats and convert the irregular ones.
My solution, not smart at all:
long DurationFixer(String duration){
long durationLong = 0;
if(duration.contains(":")){
DateFormat sdf = new SimpleDateFormat("mm:ss");
try {
Date durationD = sdf.parse(duration);
Date zeroSec = sdf.parse("00:00:00");
durationLong = durationD.getTime() - zeroSec.getTime();
} catch (Exception e) {
durationLong = (Long.parseLong(duration))/1000;
}
}
else{
String r = "";
if(duration.contains("s")){
for (int i = 0; i < duration.length()-2; i ++) {
if ((duration.charAt(i) == '.'))
break;
else
r += duration.charAt(i);
}
}
durationLong = Long.valueOf(r);
}
return durationLong;
}
If someone could find a better solution, please, tell me.
Thanks everybody!