0

0

使用 Stax2 自定义属性值转义:精准控制 XML 属性中字符的编码行为

花韻仙語

花韻仙語

发布时间:2026-02-07 15:53:53

|

625人浏览过

|

来源于php中文网

原创

使用 Stax2 自定义属性值转义:精准控制 XML 属性中字符的编码行为

本文详解如何通过 stax2 的 `p_attr_value_escaper` 属性配合自定义 `escapingwriterfactory`,实现对 xml 属性值中预转义字符(如 ` `)的“零干预”输出,避免被二次转义为 ` `。

在使用标准 javax.xml.stream.XMLStreamWriter 或默认 Stax2 实现生成 XML 时,一个常见痛点是:当开发者主动传入已按 XML 规范转义的字符串(例如 "This That",其中 表示换行符的字符引用),写入器仍会将其视为普通文本,对其中的 & 符号进行额外转义,最终生成 —— 这破坏了原始意图,导致解析时无法还原为换行符。

Stax2(特别是 Woodstox 实现)提供了精细的转义控制能力,其关键在于 XMLOutputFactory2.P_ATTR_VALUE_ESCAPER 属性。但需特别注意:该属性不接受布尔值(如 true/false),而必须绑定一个实现了 org.codehaus.stax2.io.EscapingWriterFactory 接口的工厂类实例。错误地传入 Boolean 是引发 ClassCastException 的根本原因(如题中所示)。

✅ 正确用法:实现并注册自定义 EscapingWriterFactory

核心思路是提供一个“透传式”工厂——它创建的 Writer 不做任何额外转义,直接将原始字符序列写入底层流。以下是一个简洁、安全的 Scala 实现:

import org.codehaus.stax2.XMLOutputFactory2
import org.codehaus.stax2.io.EscapingWriterFactory
import javax.xml.stream.XMLStreamWriter
import java.io.{File, FileOutputStream, Writer, OutputStream}
import java.lang.IllegalArgumentException

class CustomXmlEscapingWriterFactory extends EscapingWriterFactory {
  override def createEscapingWriterFor(writer: Writer, encoding: String): Writer =
    new Writer {
      override def write(cbuf: Array[Char], off: Int, len: Int): Unit =
        writer.write(cbuf, off, len)
      override def flush(): Unit = writer.flush()
      override def close(): Unit = writer.close()
    }

  override def createEscapingWriterFor(outputStream: OutputStream, encoding: String): Writer =
    throw new IllegalArgumentException("OutputStream-based escaping not supported in this implementation")
}

// 使用示例
val file = new File("stax2test.xml")
val fos = new FileOutputStream(file)
val outputFactory = XMLOutputFactory2.newInstance().asInstanceOf[XMLOutputFactory2]

// ✅ 关键:传入工厂类的实例,而非 Boolean!
outputFactory.setProperty(
  XMLOutputFactory2.P_ATTR_VALUE_ESCAPER,
  new CustomXmlEscapingWriterFactory()
)

val writer = outputFactory.createXMLStreamWriter(fos)
try {
  writer.writeStartDocument()
  writer.writeStartElement("elem1")
  writer.writeAttribute("att1", "This 
 That") // 期望原样输出
  writer.writeEndElement()
  writer.writeEndDocument()
} finally {
  writer.close()
  fos.close()
}

执行后,生成的 XML 文件内容为:

闪电说
闪电说

AI语音输入法

下载

完全符合预期 —— 未被二次转义。

⚠️ 重要注意事项

  • 工厂实例化时机:务必在调用 createXMLStreamWriter(...) 之前 设置属性,否则无效。
  • 编码一致性:createEscapingWriterFor 方法接收 encoding 参数,应确保与 XMLOutputFactory 配置的编码(如 UTF-8)一致;本例中因透传,可忽略该参数,但生产环境建议校验。
  • OutputStream 支持:示例中禁用了 OutputStream 版本的工厂方法(抛出异常)。若需支持字节流(如直接写入 FileOutputStream),需在 createEscapingWriterFor(OutputStream, ...) 中返回一个基于 OutputStreamWriter 的 Writer,并指定正确编码。
  • 依赖版本:确保使用兼容的 Woodstox 版本(如 woodstox-core 6.4+)及 Stax2 API(stax2-api 4.2+),旧版本接口可能有差异。
  • 适用场景:此方案适用于明确知晓输入字符串已合规转义的场景。若输入为原始未转义文本(如含 &,

? 总结

Stax2 的 P_ATTR_VALUE_ESCAPER 是解决 XML 属性值精细化转义需求的利器。成功的关键在于理解其设计契约:它要求一个 EscapingWriterFactory 实例,而非开关标志。通过实现一个“无操作”(no-op)工厂,即可让写入器信任并原样输出已转义内容。这不仅解决了 类问题,也为更复杂的自定义转义逻辑(如条件转义、特定字符白名单等)提供了清晰的扩展路径。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
java中boolean的用法
java中boolean的用法

在Java中,boolean是一种基本数据类型,它只有两个可能的值:true和false。boolean类型经常用于条件测试,比如进行比较或者检查某个条件是否满足。想了解更多java中boolean的相关内容,可以阅读本专题下面的文章。

354

2023.11.13

java boolean类型
java boolean类型

本专题整合了java中boolean类型相关教程,阅读专题下面的文章了解更多详细内容。

34

2025.11.30

pdf怎么转换成xml格式
pdf怎么转换成xml格式

将 pdf 转换为 xml 的方法:1. 使用在线转换器;2. 使用桌面软件(如 adobe acrobat、itext);3. 使用命令行工具(如 pdftoxml)。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

1915

2024.04.01

xml怎么变成word
xml怎么变成word

步骤:1. 导入 xml 文件;2. 选择 xml 结构;3. 映射 xml 元素到 word 元素;4. 生成 word 文档。提示:确保 xml 文件结构良好,并预览 word 文档以验证转换是否成功。想了解更多xml的相关内容,可以阅读本专题下面的文章。

2099

2024.08.01

xml是什么格式的文件
xml是什么格式的文件

xml是一种纯文本格式的文件。xml指的是可扩展标记语言,标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言。想了解更多相关的内容,可阅读本专题下面的相关文章。

1104

2024.11.28

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

424

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

213

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1514

2023.10.24

Golang处理数据库错误教程合集
Golang处理数据库错误教程合集

本专题整合了Golang数据库错误处理方法、技巧、管理策略相关内容,阅读专题下面的文章了解更多详细内容。

2

2026.02.06

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 3.3万人学习

C# 教程
C# 教程

共94课时 | 8.8万人学习

Java 教程
Java 教程

共578课时 | 59.5万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号