简体   繁体   中英

java exslt date-time() producing unintended output

While doing xslt transformation the timezone is serialized in a weird way

I tried switching implementations between xalan and jaxen but no change was observed.

Tried to look into formatting the date manualy but can't seem to find the way to add time zone (eg, +05:30 or -08:00) using that.

Has anybody faced a similar problem like this?

Result Produced

<?xml version="1.0" encoding="UTF-8"?>
<Test xmlns:date="http://exslt.org/dates-and-times" version="1.0">
    2019-06-20T10:23:31+05:1800000
</Test>

Expected Result

<?xml version="1.0" encoding="UTF-8"?>
<Test xmlns:date="http://exslt.org/dates-and-times" version="1.0">
    2019-06-20T10:23:31+05:30
</Test>

My sample code is as below

Main.java

package test;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.TimeZone;

import static java.nio.charset.StandardCharsets.UTF_8;

public class Main {
    public static void main(String[] args) {
        printTransformed(TimeZone.getTimeZone("Asia/Kolkata"));
    }

    private static void printTransformed(TimeZone timeZone) {
        TimeZone.setDefault(timeZone);
        try {
            final StreamSource source = new StreamSource(
                    Files.newInputStream(
                            Paths.get(PrintAllTimeZones1.class.getResource("/input.xml").toURI())));

            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            Templates xsltTemplate = transformerFactory.newTemplates(
                    new StreamSource(Files.newInputStream(
                            Paths.get(Application.class.getResource("/test.xslt").toURI()))));

            final Transformer transformer = xsltTemplate.newTransformer();
            transformer.setOutputProperty(OutputKeys.ENCODING, UTF_8.name());
            final ByteArrayOutputStream out = new ByteArrayOutputStream();
            final StreamResult result = new StreamResult(out);
            transformer.transform(source, result);
            System.out.println(result.getOutputStream().toString());
        } catch (IOException e) {
            e.printStackTrace();
        } catch (URISyntaxException e) {
            e.printStackTrace();
        } catch (TransformerException e) {
            e.printStackTrace();
        }
    }
}

input.xml

<?xml version="1.0" encoding="UTF-8" ?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
    <SOAP-ENV:Header/>
    <SOAP-ENV:Body>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

test.xslt

<Test version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:date="http://exslt.org/dates-and-times">
    <xsl:value-of select="date:date-time()"/>
</Test>

build.gradle

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:2.1.4.RELEASE")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

bootJar {
    baseName = 'gs-spring-boot'
    version =  '0.1.0'
}

repositories {
    mavenCentral()
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web")
    compile 'jaxen:jaxen'
    testCompile("junit:junit")
    compile group: 'xalan', name: 'xalan', version: '2.7.2'


    compile group: 'xmlunit', name: 'xmlunit', version: '1.6'

    compile group: 'org.apache.avro', name: 'avro', version: '1.9.0'

}

The reason for getting 2019-06-20T10:23:31+05:1800000 is because the xalan's ExsltDatetime implementation would add the GMT offset along with DST offset ( 5.5 hours). But there looks to be a bug in xalan implementation when calculating the offset in hours & minutes.

Code to offset in xalan's ExsltDatetime class :

int offset = cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET);
// If there is no offset, we have "Coordinated
// Universal Time."
if (offset == 0)
    buff.append('Z');
 else {
    // Convert milliseconds to hours and minutes
     int hrs = offset/(60*60*1000);
     // In a few cases, the time zone may be +/-hh:30.
      int min = offset%(60*60*1000);
      char posneg = hrs < 0? '-': '+';
      buff.append(posneg + formatDigits(hrs) + ':' + formatDigits(min));
  }

The above code gives offset in hrs as 5, which is good, but the minutes offset is calculated as 1800000, which is incorrect.

The else part should be calculating the minutes correctly from remaining offset as below:

  // Convert milliseconds to hours and minutes
  int hrs = offset/(60*60*1000);
  // In a few cases, the time zone may be +/-hh:30.
  //get the remaining offset in ms
  offset -= (hrs*60*60*1000);
  //convert remaining offset into minutes
  int min = offset/(60*1000);
  char posneg = hrs < 0? '-': '+';
  buff.append(posneg + formatDigits(hrs) + ':' + formatDigits(min));

The above is the corrected code, which correctly returns minutes as 30.

To use a different/simple date formatter for current date in your XSLT, you can use:

<Test version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:date="xalan://java.text.SimpleDateFormat"
        xmlns:java="http://xml.apache.org/xslt/java">
               <xsl:variable name="iso-date"
                select='date:new("yyyy-MM-dd&apos;T&apos;hh:mm:ssXXX")' />
    <xsl:value-of select="java:format($iso-date, java:java.util.Date.new())"/>
</Test>

You can also try XSLT 2.0 formatting functions

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM