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

如何在Java中使用Saxon为XQuery配置多输入文件参数?

解决Java调用XQuery处理JSON的报错与多文件支持问题

咱们先搞定那个烦人的XML解析报错,再一步步实现多JSON文件的处理支持:

一、修复SXXP0003报错:别把JSON当XML解析

你遇到的SXXP0003: Error reported by XML parser: Content is not allowed in prolog错误,根源是你把JSON输入流当成XML文档来解析了。JSON不是XML格式,XML解析器看到开头的{就会认为序言(XML文档开头的声明部分)有非法内容,直接报错。

正确的做法是:直接把JSON解析成Saxon支持的XDM(XQuery Data Model)对象,作为外部变量传给XQuery,而不是转换成XML节点。

二、修改XQuery脚本,支持外部参数与多文件输入

我们需要把原来硬编码的JSON文件路径改成接收外部变量,同时支持处理多个JSON对象。修改后的XQuery.xq如下:

xquery version "3.1";
declare namespace array = "http://www.w3.org/2005/xpath-functions/array";
declare namespace map = "http://www.w3.org/2005/xpath-functions/map";
declare namespace output = "http://www.w3.org/2010/xslt-xquery-serialization";

declare option output:method "json";
declare option output:indent "yes";
declare variable $input-json as item()* external; (: 接收多个JSON对象的序列 :)

array {
  for $j in $input-json (: 遍历每个输入的JSON对象 :)
  where ("Fred" = $j?FirstName or 30 != $j?Age)
  return
    array {
      for $i in (1 to $j?Phone => array:size())
      let $e := $j?Phone($i)
      where ($e?type = "home" or fn:matches($e?type, "^mob.*$"))
      return map {
        "Name (First)": data($j?FirstName),
        "Name (Last)": data($j?Surname),
        "age": data($j?Age),
        "Phone": data($e?number),
        "ConstantValue": "TEST"
      }
    }
}

关键改动点:

  • 新增declare variable $input-json as item()* external;:声明一个外部变量,接收多个JSON对象的序列
  • 外层新增for $j in $input-json循环:遍历每个输入的JSON文件内容
  • 保留了你原来的过滤和转换逻辑,确保功能不变

三、修改Java代码,正确传递JSON参数并支持多文件

现在调整Java代码,把每个JSON文件解析成XDM对象,打包成序列传给XQuery,同时去掉错误的XML解析逻辑:

import net.sf.saxon.Configuration;
import net.sf.saxon.s9api.*;
import org.junit.Test;
import org.springframework.util.StreamUtils;

import java.io.*;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

import static org.junit.Assert.assertEquals;

public class XQueryTest {

    @Test
    public void testMultiJsonXQuery() throws Exception {
        // 支持传入多个JSON文件路径
        runXQuery(List.of("/1.json", "/2.json"), "/XQuery.xq", "/Multi_Output.json");
    }

    private void runXQuery(List<String> dataFiles, String xQueryFile, String expectedOutput) throws Exception {
        // 解析所有输入JSON文件为XDM对象
        List<XdmItem> inputItems = new ArrayList<>();
        Processor processor = new Processor(false);
        JsonParser jsonParser = processor.newJsonParser();

        for (String dataFile : dataFiles) {
            try (InputStream dataStream = getClass().getResourceAsStream(dataFile)) {
                XdmValue jsonValue = jsonParser.parse(new InputSource(dataStream));
                inputItems.addAll(jsonValue.asList());
            }
        }

        // 读取XQuery脚本
        try (InputStream xQueryStream = getClass().getResourceAsStream(xQueryFile)) {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            run(processor, inputItems, xQueryStream, outputStream);

            // 验证输出
            String json = outputStream.toString();
            String expected = StreamUtils.copyToString(
                    getClass().getResourceAsStream(expectedOutput),
                    Charset.defaultCharset()
            );
            assertEquals(expected, json);
        }
    }

    private static void run(Processor processor, List<XdmItem> inputItems, InputStream queryStream, OutputStream output) throws SaxonApiException {
        XQueryCompiler compiler = processor.newXQueryCompiler();
        XQueryExecutable executor = compiler.compile(new InputSource(queryStream));
        XQueryEvaluator evaluator = executor.load();

        // 设置外部变量:把多个JSON对象序列传给$input-json
        QName inputQName = new QName("input-json");
        evaluator.setExternalVariable(inputQName, new XdmSequence(inputItems));

        // 配置JSON序列化
        Serializer serializer = processor.newSerializer(output);
        serializer.setOutputProperty(Serializer.Property.METHOD, "json");
        serializer.setOutputProperty(Serializer.Property.INDENT, "yes");

        evaluator.run(serializer);
    }
}

关键改动点:

  1. 用Saxon的JsonParser解析JSON:避免了XML解析的错误,直接把JSON转换成XDM对象(符合XQuery的数据模型)
  2. 支持多文件输入:通过List<String> dataFiles接收多个JSON文件路径,逐个解析后加入序列
  3. 正确传递外部变量:用XdmSequence把多个JSON对象打包,传给XQuery中声明的$input-json变量
  4. 移除错误的XML节点处理:删掉了SAXSource、DocumentBuilder相关的代码,不再把JSON当XML处理

四、测试与验证

  • 把2.json放到资源目录下,格式和1.json类似即可
  • 运行testMultiJsonXQuery方法,会同时处理1.json和2.json,输出合并后的JSON结果

这样既解决了原来的XML解析报错,又实现了多JSON文件的处理需求~

内容的提问来源于stack exchange,提问作者Roeland Van Heddegem

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 03:55:11