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

Saxon 10.6 HE中XSLT转换XML时NotSerializableException异常排查及无Serializer实现方案咨询

解决Saxon XSLT转换中的WriteAbortedException问题及替代Serializer的方法

我来帮你分析并解决这个问题,同时给出不使用Serializer的转换方案。

错误原因分析

你遇到的java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: net.sf.saxon.om.StructuredQName异常,核心原因是Saxon内部的StructuredQName类未实现Serializable接口,但在转换过程中该对象被触发了序列化操作。结合你的代码来看,可能的触发场景有两个:

  • 无效的输入XML:你的输入XML存在语法错误——它包含了<create>和<update>两个根节点,而XML规范要求文档必须有且仅有一个根元素。这种无效输入可能导致Saxon在解析和处理过程中产生异常,进而触发内部对象的序列化尝试。
  • XSLT分组逻辑中的潜在问题:你的my:merge函数使用group-by="path()"分组,虽然fn:path()返回的是字符串,但Saxon在处理分组键时可能内部使用了StructuredQName来表示节点名称,在递归处理节点的场景下导致该对象被暴露到需要序列化的上下文。

解决方案

步骤1:修复输入XML的有效性

首先将输入XML包裹在一个根元素中,修正语法错误:

<root>
  <create> 
    <article> 
      <identifier>Test</identifier> 
    </article> 
    <article> 
      <identifier>Test123</identifier> 
    </article> 
  </create> 
  <update> 
    <article> 
      <identifier>Test</identifier> 
    </article> 
  </update>
</root>

步骤2:调整XSLT分组逻辑(可选)

如果修复XML后仍出现异常,可以修改my:merge函数的分组方式,改用自定义路径构造逻辑替代fn:path(),避免依赖Saxon内部的QName处理:

<xsl:function name="my:merge" as="node()*">
  <xsl:param name="node1" as="node()*"/>
  <xsl:param name="node2" as="node()*"/>
  <!-- 改用自定义路径构造逻辑替代fn:path() -->
  <xsl:for-each-group select="$node1, $node2" group-by="my:get-node-path(.)">
    <xsl:copy>
      <xsl:sequence select="my:merge(@*, current-group()[2]/@*)"/>
      <xsl:sequence select="my:merge(node(), current-group()[2]/node())"/>
    </xsl:copy>
  </xsl:for-each-group>
</xsl:function>

<!-- 自定义获取节点路径的函数 -->
<xsl:function name="my:get-node-path" as="xs:string">
  <xsl:param name="node" as="node()"/>
  <xsl:choose>
    <xsl:when test="$node/parent::*">
      <xsl:value-of select="concat(my:get-node-path($node/parent::*), '/', local-name($node))"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="concat('/', local-name($node))"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:function>

步骤3:升级Saxon版本

Saxon 10.6是较旧的版本,可能存在已知的序列化相关bug。建议升级到最新的稳定版本(比如Saxon 12.x),新版本通常会修复这类兼容性问题。

不使用Serializer的转换方法

当然可以不用Serializer,直接使用StreamResult作为输出目标,代码更简洁:

Source xslt = new StreamSource(new StringReader(inputXSLT)); 
Source xml = new StreamSource(new StringReader(inputXML)); 
StringWriter transformedXML = new StringWriter(); 

Processor processor = new Processor(false); 
XsltCompiler compiler = processor.newXsltCompiler(); 
XsltExecutable stylesheet = compiler.compile(xslt); 

Xslt30Transformer transformer = stylesheet.load30(); 
// 直接使用StreamResult替代Serializer
transformer.transform(xml, new StreamResult(transformedXML)); 

outputXML = transformedXML.toString();

如果需要设置输出格式(比如缩进、编码),可以直接在XSLT的<xsl:output>节点中配置,无需额外的Serializer配置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 09:47:28