JAXB流式写入文件时如何移除重复元素的空xmlns=""?
JAXB流式编组处理大数据量XML的命名空间问题解决
我通过xjc生成了数据对象,需要将其编组为XML并写入文件,不能修改生成的对象及package-info.java等文件。MainElem对象包含一个RepeatingElem列表,最初采用常规方式编组时,输出的XML合法且可通过验证,但由于RepeatingElem数据量大、数量多达数千个,出现了内存溢出问题。
初始非流式实现
JAXBContext jaxbContext = JAXBContext.newInstance(MainElem.class); Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); StringWriter sw = new StringWriter(); jaxbMarshaller.marshal(mainElemObj, sw);
输出XML示例:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <mainelem xmlns="http://schema.blah.com/xx/xxx/1"> <repeatingelem> <id>123344567</id> <type>A</type> </repeatingelem> <repeatingelem> <id>98775312</id> <type>B</type> </repeatingelem> </mainelem>
流式改造遇到的问题
为解决内存溢出,改用流式编组方案逐对象写入文件,代码如下:
JAXBContext context = JAXBContext.newInstance(RepeatingElem.class); Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE); XMLOutputFactory xof = XMLOutputFactory.newFactory(); xof.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true); XMLStreamWriter xmlOut = xof.createXMLStreamWriter(new FileOutputStream("myXmlFiel")); xmlOut.setDefaultNamespace("http://schema.blah.com/xx/xxx/1"); xmlOut.writeStartDocument(); xmlOut.writeStartElement("mainelem"); for(RepeatingElem elem: elemList){ JAXBElement<RepeatingElem> element = new JAXBElement<>(new QName(null, "repeatingelem"), RepeatingElem.class, elem); marshaller.marshal(element, xmlOut); } xmlOut.writeEndDocument(); xmlOut.close();
但生成的XML不合法且无法验证,RepeatingElem元素出现空xmlns=""和ns2前缀,示例如下:
<?xml version="1.0" ?> <mainelem xmlns="http://schema.blah.com/xx/xxx/1"> <repeatingelem xmlns="" xmlns:ns2="http://schema.blah.com/xx/xxx/1"> <ns2:id>123344567</ns2:id> <ns2:type>A</ns2:type> </repeatingelem> <repeatingelem xmlns="" xmlns:ns2="http://schema.blah.com/xx/xxx/1"> <ns2:id>98775312</ns2:id> <ns2:type>B</ns2:type> </repeatingelem> </mainelem>
尝试过调整IS_REPAIRING_NAMESPACES、setDefaultNamespace等命名空间相关配置,甚至将JAXB版本升级到4.0.4都无法解决空xmlns=""的问题。后来移除部分配置并添加xmlOut.writeAttribute解决了空命名空间,但ns2前缀依然存在,导致XML无法通过验证。
最终解决方案
通过修改JAXBElement的QName,指定对应命名空间和默认前缀,彻底解决了问题:
JAXBElement<RepeatingElem> element = new JAXBElement<>(new QName("http://schema.blah.com/xx/xxx/1", "repeatingelem", XMLConstants.DEFAULT_NS_PREFIX), RepeatingElem.class, elem);
对应的XSD定义
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schema.blah.com/xx/xxx/1" targetNamespace="http://schema.blah.com/xx/xxx/1" elementFormDefault="qualified" attributeFormDefault="unqualified" version="1.0.0"> <xsd:element name="mainelem"> <xsd:complexType> <xsd:sequence> <xsd:element name="repeatingelem" type="Rep" minOccurs="0" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:complexType name="Rep"> <xsd:element name="id" type="xsd:string"/> <xsd:element name="type" type="xsd:string"/> ... </xsd:complexType> </xsd:schema>
内容的提问来源于stack exchange,提问作者StarMcSnow
相关产品推荐
相关产品推荐

