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

如何使用Saxon-HE库对Java Map执行XPath 3.1查询?

用Saxon-HE实现对Java Map的XPath 3.1查询(替代JXPathContext)

可以用Saxon-HE实现对Java Map的XPath查询,下面是具体的迁移方案和代码实现:

核心思路

Saxon-HE支持将Java Map自动映射为XPath 3.1的map类型,配合S9API接口可以实现类似JXPath的Map查询能力。关键步骤包括:

  • 配置Saxon允许访问Java对象和方法
  • 将JXPath风格的点分隔路径转换为XPath 3.1的map链式访问语法
  • 把Java Map作为XPath上下文项传入执行查询
  • 处理查询结果并转换为Java对象

完整代码实现

import net.sf.saxon.Configuration;
import net.sf.saxon.s9api.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class SaxonMapXpathUtils {

    public static Object getXpathValueFromContentMap(String name, Map<String, Object> content, boolean list) {
        // 初始化Saxon处理器(false表示不启用Schema验证)
        Processor processor = new Processor(false);
        XPathCompiler compiler = processor.newXPathCompiler();
        
        // 配置Saxon以支持Java对象和Map的访问
        Configuration config = processor.getUnderlyingConfiguration();
        config.setBooleanProperty(FeatureKeys.ALLOW_JAVA_METHODS, true);
        config.setBooleanProperty(FeatureKeys.ALLOW_EXTERNAL_FUNCTIONS, true);
        // 将Java集合自动转换为XPath序列,方便处理列表结果
        config.setBooleanProperty(FeatureKeys.TREAT_JAVA_COLLECTIONS_AS_XPATH_SEQUENCES, true);
        
        // 将JXPath风格的路径转换为XPath 3.1的map访问表达式
        String xpathExpr = buildMapAccessExpression(name);
        
        try {
            XPathExecutable executable = compiler.compile(xpathExpr);
            XPathSelector selector = executable.load();
            
            // 将Java Map设置为XPath上下文项(Saxon会自动转换为XPath map类型)
            selector.setContextItem(processor.newAtomicValue(content));
            
            if (list) {
                // 处理列表模式:将XPath序列转换为Java List
                List<Object> resultList = new ArrayList<>();
                XdmValue xdmValue = selector.evaluate();
                for (XdmItem item : xdmValue) {
                    resultList.add(item.getValue());
                }
                // 空列表返回null,对应原代码的异常逻辑
                return resultList.isEmpty() ? null : resultList;
            } else {
                // 处理单个值模式:获取单个结果
                XdmItem item = selector.evaluateSingle();
                return item != null ? item.getValue() : null;
            }
        } catch (SaxonApiException e) {
            // 捕获编译或执行异常,返回null对应原代码的JXPathNotFoundException
            return null;
        }
    }

    /**
     * 将JXPath风格的点分隔路径(如"foo.bar")转换为XPath 3.1的map链式访问表达式(如"$.?foo?bar")
     * @param name JXPath路径字符串
     * @return 对应的XPath 3.1表达式
     */
    private static String buildMapAccessExpression(String name) {
        if (name == null || name.isBlank()) {
            return "$.";
        }
        String[] keys = name.split("\\.");
        StringBuilder exprBuilder = new StringBuilder("$.?");
        exprBuilder.append(keys[0]);
        for (int i = 1; i < keys.length; i++) {
            exprBuilder.append("?").append(keys[i]);
        }
        return exprBuilder.toString();
    }
}

关键细节说明

  • 配置项作用:
    • ALLOW_JAVA_METHODS:允许XPath调用Java对象的方法
    • ALLOW_EXTERNAL_FUNCTIONS:支持外部函数(包括Java方法映射的函数)
    • TREAT_JAVA_COLLECTIONS_AS_XPATH_SEQUENCES:让Java集合(如List)自动转换为XPath序列,方便迭代获取列表结果
  • 表达式转换:JXPath的"foo.bar"对应XPath 3.1的$.?foo?bar,这种语法可以直接访问嵌套Map的层级结构
  • 结果转换:通过XdmItem.getValue()将Saxon的XDM类型转换为对应的Java对象,保持和原代码一致的返回值类型
  • 异常处理:用SaxonApiException捕获所有查询相关异常,返回null对应原代码中JXPathNotFoundException的处理逻辑

内容的提问来源于stack exchange,提问作者Tim

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 07:05:20