在JAXB中使用xs:any和混合内容维护空白



我有一个带有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, laxskip,但都没有帮助。

遇到类似的问题后,我可以提出以下解决方案(对于这个特定的场景,与其他一些复杂的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任意内容"属性

相关内容

  • 没有找到相关文章

最新更新