我有一个带有xs:any元素的模式。此元素可能包含具有混合内容的其他元素。我正在尝试使用JAXB将其分解为Java对象(使用'any'作为元素)。
从schema:
<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:如何在解组过程中保持源XML中的连续空格),但这对元素之间的空白没有影响。我试过将processContents
设置为strict
, lax
和skip
,但都没有帮助。
遇到类似的问题后,我可以提出以下解决方案(对于这个特定的场景,与其他一些复杂的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任意内容"属性