如何在不修改实体类注解前提下用JAXB正确序列化含CDATA的XML字符串
解决方案
方案1:直接解析XML片段为DOM节点挂载(匹配你给出的预期输出)
该方案无需使用CDATA,直接将你要插入的XML片段解析为DOM节点树后挂载到myTag节点下,序列化后内部XML会作为合法节点输出,无转义:
import java.io.ByteArrayInputStream import java.io.StringWriter import javax.xml.bind.JAXB import javax.xml.parsers.DocumentBuilderFactory fun main() { val documentBuilderFactory = DocumentBuilderFactory.newInstance() val documentBuilder = documentBuilderFactory.newDocumentBuilder() val document = documentBuilder.newDocument() val myElement = document.createElement("myTag") // 解析内部XML片段为DOM节点 val innerXml = "<xml><a>text</a></xml>" val innerDoc = documentBuilder.parse(ByteArrayInputStream(innerXml.toByteArray())) // 将解析好的节点导入当前Document上下文并挂载 val importedInnerNode = document.importNode(innerDoc.documentElement, true) myElement.appendChild(importedInnerNode) val myObject = MyObject().apply { element = myElement } val writer = StringWriter() JAXB.marshal(myObject, writer) println(writer.toString()) }
输出结果完全匹配你给出的预期格式。
方案2:保留CDATA格式不转义
如果你需要将内部XML作为纯文本存储在CDATA段中,不想让它被识别为父结构的子节点,可以自定义JAXB序列化器的转义逻辑,跳过CDATA内容的转义:
import java.io.StringWriter import javax.xml.bind.JAXBContext import javax.xml.bind.Marshaller import javax.xml.parsers.DocumentBuilderFactory import com.sun.xml.bind.marshaller.CharacterEscapeHandler fun main() { val documentBuilderFactory = DocumentBuilderFactory.newInstance() val document = documentBuilderFactory.newDocumentBuilder().newDocument() val myElement = document.createElement("myTag") myElement.appendChild(document.createCDATASection("<xml><a>text</a>")) val myObject = MyObject().apply { element = myElement } // 自定义序列化配置 val jaxbContext = JAXBContext.newInstance(MyObject::class.java) val marshaller = jaxbContext.createMarshaller() marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true) // 禁用转义逻辑(适配JDK默认的Sun JAXB实现) marshaller.setProperty("com.sun.xml.bind.characterEscapeHandler", CharacterEscapeHandler { chars, start, length, _, writer -> writer.write(chars, start, length) } ) val writer = StringWriter() marshaller.marshal(myObject, writer) println(writer.toString()) }
该方案输出的CDATA段内容不会被转义,内部XML会完整保留在<![CDATA[...]]>包裹中。
内容的提问来源于stack exchange,提问作者J.Doe
相关产品推荐
相关产品推荐

