You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Saxon 10 DateTime变量被识别为字符串及序列化异常求助

Saxon 10迁移中的两个问题解决方案

一、DateTime变量被识别为字符串的问题

问题现象

原有表达式current-dateTime() - $datetime报错,提示操作数类型不匹配(xs:dateTimestamp和xs:string),Saxon 10将$datetime识别为字符串类型,而Saxon 9中可直接按DateTime类型处理。

原因

Saxon 10.5开始将AtomicValue标记为非序列化,导致Java端传入的DateTimeValue对象在XPath上下文传递过程中无法保持原有类型,被降级为字符串。

解决方案

  1. 临时修复:强制类型转换
    保留当前使用的强制转换方式,确保表达式正常执行:

    current-dateTime() - xs:dateTime($datetime)
    
  2. 根本修复:正确注册变量类型
    在Java代码向XPath上下文注入$datetime变量时,显式指定其类型为xs:dateTime,而非直接传递字符串或未类型化对象:

    // 示例:基于Saxon API的变量注册
    XPathCompiler compiler = processor.newXPathCompiler();
    // 声明变量并指定类型为xs:dateTime
    compiler.declareVariable(new QName("datetime"), ItemType.DATE_TIME);
    // 执行时传入DateTimeValue对象
    XPathSelector selector = executable.load();
    selector.setVariable(new QName("datetime"), dateTimeValue);
    

    此方式下Saxon会直接识别变量为xs:dateTime类型,无需手动转换。

二、深拷贝时的序列化异常问题

问题现象

调用completeCopy方法执行深拷贝时抛出java.io.NotSerializableException,涉及XSDateTimeDummyProperty类和内部的DateTimeValue对象。

原因

  1. XSDateTimeDummyProperty及其父类SaxonParentProperty未实现Serializable接口;
  2. 即使实现Serializable,Saxon 10.5后的AtomicValue(包括DateTimeValue)被标记为非序列化,内部obj字段无法被序列化。

解决方案

放弃基于序列化的深拷贝方式,改用基于对象内容的手动复制:

  1. 修改completeCopy方法,通过DateTimeValue的字符串表示重新创建对象:
    public static <T extends XSDateTimeDummyProperty> T completeCopy(T orig) {
        if (orig == null) {
            return null;
        }
        try {
            // 创建实例副本
            T copy = orig.getClass().getDeclaredConstructor().newInstance();
            // 基于原有DateTimeValue的字符串值重新生成对象
            if (orig.obj != null) {
                String dateTimeStr = orig.obj.getStringValue();
                ConversionResult conversionResult = DateTimeValue.makeDateTimeValue(dateTimeStr, ConversionRules.DEFAULT);
                copy.obj = (DateTimeValue) conversionResult;
            }
            return copy;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
  2. 可选:保留序列化能力的适配
    若需保留序列化功能,可将obj字段标记为transient,并实现readObject/writeObject方法手动处理DateTimeValue的序列化逻辑:
    public class XSDateTimeDummyProperty extends SaxonParentProperty<DateTimeValue> implements Serializable {
        private static final long serialVersionUID = 1L;
        transient DateTimeValue obj;
    
        private void writeObject(ObjectOutputStream out) throws IOException {
            out.defaultWriteObject();
            // 写入DateTimeValue的字符串表示
            out.writeObject(obj != null ? obj.getStringValue() : null);
        }
    
        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
            in.defaultReadObject();
            // 读取字符串并重新转换为DateTimeValue
            String dateTimeStr = (String) in.readObject();
            if (dateTimeStr != null) {
                ConversionResult conversionResult = DateTimeValue.makeDateTimeValue(dateTimeStr, ConversionRules.DEFAULT);
                this.obj = (DateTimeValue) conversionResult;
            }
        }
    
        // 原有方法...
    }
    

内容的提问来源于stack exchange,提问作者Siddhant K.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 17:40:23