我有一个带有xs:any元素的模式。此元素可能包含具有混合内容的其他元素。我试图使用JAXB将其解组为Java对象(使用' any'作为元素)。
来自架构:
<xs:element name="a">
<xs:complexType>
<xs:sequence>
<xs:any processContents="lax"/>
</xs:sequence>
</xs:complexType>
</xs:element>
一般来说,这是有效的。但是当处理具有混合内容的元素时,嵌套节点之间的空白将丢失。
的test.xml:
<a><foo><b>Hello</b> <i>World</i></foo></a>
像这样解组:
JAXBContext jc = JAXBContext.newInstance(A.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
InputStream inputStream = this.getClass().getResourceAsStream("/data/test.xml");
A a = (A) unmarshaller.unmarshal(inputStream);
Marshaller marshaller = jc.createMarshaller();
marshaller.marshal(a, System.out);
结果如下:
<a><foo><b>Hello</b><i>World</i></foo></a>
我丢失了<foo>
元素的子标记之间的空格。我确定这是将空白带到这里的unmarshal步骤,但我确实需要它来实现往返。
请注意,它只删除了仅限空白的文本内容。这可以按预期工作:
<a><foo><b>Hello</b> to you <i>World</i></foo></a>
我尝试添加xml:space="preserve"
(例如,参见JAXB: How to keep consecutive spaces as they are in source XML during unmarshalling),但这对元素之间的空白没有影响。我已经尝试将processContents
设置为strict
,lax
和skip
,但没有一个帮助过。
答案 0 :(得分:0)
面对类似的问题后,我可以提出以下解决方案(对于这种特定情况,对于某些其他复杂的XML结构而言,它并不完美)。
package com.stackoverflow.answers;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlMixed;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.transform.stream.StreamSource;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.w3c.dom.Element;
public class XmlAnyElementWithWhiteSpacesTest {
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "a")
private static class A {
@XmlAnyElement
@XmlMixed
private List<Element> elements;
}
private static final String SAMPLE = "<a><foo><b>Hello</b> <i>World</i></foo></a>";
@Test
public void shouldParseAndSerializeKeepingWhiteSpaceElements() throws JAXBException {
// given
JAXBContext jc = JAXBContext.newInstance(A.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
InputStream inputStream = new ByteArrayInputStream(SAMPLE.getBytes(StandardCharsets.UTF_8));
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
// when
JAXBElement<A> a = unmarshaller.unmarshal(new StreamSource(inputStream), A.class);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
marshaller.marshal(a.getValue(), outputStream);
String actual = new String(outputStream.toByteArray(), StandardCharsets.UTF_8);
// then
assertEquals(SAMPLE, actual);
}
}
关键点是:
@XmlMixed
批注StreamSource
的使用方式您可以将List<Object>
或List<Element>
用于“ XML任意内容”属性。