如何使用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
相关产品推荐
相关产品推荐

