我正在尝试解码 DICOM Sequence VR type它作为 XML CLOB 存储在数据库中。根据标准,序列可以包含属性以及子序列。可供引用的示例是 Content Sequence属性。
因此,我在 JAXB DTO 中使用 @XmlMixed
来处理子属性也可能是序列的情况。但是,在编码未编码的 XML 时,生成的输出只是根元素,没有子元素。
下面是我的输入 XML,表示上述内容序列。
<Root>
<ps>
<p name="0040A010" vt="8">HAS CONCEPT MOD</p>
<p name="0040A040" vt="8">CODE</p>
<p name="0040A043" vt="8">
<ps>
<p name="00080100" vt="8">121049</p>
<p name="00080102" vt="8">DCM</p>
<p name="00080104" vt="8">Language of Content Item and Descendants
</p>
</ps>
</p>
<p name="0040A168" vt="8">
<ps>
<p name="00080100" vt="8">eng</p>
<p name="00080102" vt="8">ISO639_2</p>
<p name="00080104" vt="8">English</p>
</ps>
</p>
</ps>
<ps>
<p name="0040A010" vt="8">HAS OBS CONTEXT</p>
<p name="0040A040" vt="8">CODE</p>
<p name="0040A043" vt="8">
<ps>
<p name="00080100" vt="8">121005</p>
<p name="00080102" vt="8">DCM</p>
<p name="00080104" vt="8">Observer Type</p>
</ps>
</p>
<p name="0040A168" vt="8">
<ps>
<p name="00080100" vt="8">121006</p>
<p name="00080102" vt="8">DCM</p>
<p name="00080104" vt="8">Person</p>
</ps>
</p>
</ps>
<ps>
<p name="0040A010" vt="8">HAS OBS CONTEXT</p>
<p name="0040A040" vt="8">PNAME</p>
<p name="0040A043" vt="8">
<ps>
<p name="00080100" vt="8">121008</p>
<p name="00080102" vt="8">DCM</p>
<p name="00080104" vt="8">Person Observer Name</p>
</ps>
</p>
<p name="0040A123" vt="8">IMAGE</p>
</ps>
<ps>
<p name="00081199" vt="8">
<ps>
<p name="00081150" vt="8">1.2.840.10008.5.1.4.1.1.4</p>
<p name="00081155" vt="8">1.3.6.1.4.1.5962.99.1.3923360762.207819601.1541521685498.13.0
</p>
<p name="00081199" vt="8">
<ps>
<p name="00081150" vt="8">1.2.840.10008.5.1.4.1.1.11.1</p>
<p name="00081155" vt="8">1.2.840.114356.2019.12.115.113.18.116.1508.6
</p>
</ps>
</p>
<p name="00750010" vt="8">GEIIS_IW</p>
<p name="007510A1" vt="8">1</p>
</ps>
</p>
<p name="0040A010" vt="8">CONTAINS</p>
<p name="0040A040" vt="8">IMAGE</p>
</ps>
</Root>
下面是用于映射绑定(bind)上述结构的类:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "p")
public class Property
{
@XmlElementRef(name = "ps", type = PropertySequence.class, required = false)
@XmlMixed
protected List<Object> content;
@XmlAttribute(name = "name", required = true)
protected String name;
public List<Object> getContent()
{
if (content == null)
{
content = new ArrayList<Object>();
}
return this.content;
}
public String getName()
{
return name;
}
public void setName(String value)
{
this.name = value;
}
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "ps")
public class PropertySequence
{
protected List<Property> property;
public List<Property> getProperty()
{
if (property == null)
{
property = new ArrayList<Property>();
}
return this.property;
}
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "Root")
public class Root
{
@XmlElement(required = true)
protected List<PropertySequence> propertySequence;
public List<PropertySequence> getPropertySequence()
{
if (propertySequence == null)
{
propertySequence = new ArrayList<PropertySequence>();
}
return this.propertySequence;
}
}
运行以下测试代码时,解码和后续编码后的输出 XML,输出仅是根标记。
try (InputStream xmlStream = Launcher.class.getResourceAsStream("/PropertySequence.xml"))
{
JAXBContext context = JAXBContext.newInstance(Root.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
Root root = (Root) unmarshaller.unmarshal(xmlStream);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(root, System.out);
}
catch (IOException | JAXBException e)
{
e.printStackTrace();
}
输出
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Root/>
最佳答案
XmlMixed 和 XmlElementRef
即使使用 XmlElementRef
,我们也无法直接将值反序列化为 PropertySequence
或 String
。不管怎样,使用 JAXBElement
会容易得多。让我们看看模型:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Root", propOrder = {"ps"})
public class Root {
protected List<PropertySequence> ps;
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "ps", propOrder = {"p"})
public class PropertySequence {
protected List<Property> p;
public List<Property> getP() {
if (p == null) {
p = new ArrayList<>();
}
return this.p;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
for (Property property : p) {
builder.append(property).append(System.lineSeparator());
}
return builder.toString();
}
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "p", propOrder = {"content"})
public class Property {
@XmlMixed
@XmlElementRef(name = "ps", type = JAXBElement.class, required = false)
protected List<Serializable> content;
@XmlAttribute(name = "name")
protected String name;
@XmlAttribute(name = "vt")
protected String vt;
@XmlTransient
public String getStringValue() {
if (content != null && content.size() == 1) {
return content.get(0).toString();
}
return null;
}
@XmlTransient
public PropertySequence getPropertySequence() {
if (content != null && content.size() == 3) {
return ((JAXBElement<PropertySequence>) content.get(1)).getValue();
}
return null;
}
public List<Serializable> getContent() {
if (content == null) {
content = new ArrayList<>();
}
return this.content;
}
public String getName() {
return name;
}
public void setName(String value) {
this.name = value;
}
public String getVt() {
return vt;
}
public void setVt(String value) {
this.vt = value;
}
@Override
public String toString() {
Object value = getStringValue();
if (value == null) {
value = getPropertySequence();
}
return "Property{" +
"content=" + value +
", name='" + name + '\'' +
", vt='" + vt + '\'' +
'}';
}
}
@XmlRegistry
public class ObjectFactory {
private final static QName ROOT_QNAME = new QName("", "Root");
private final static QName PropertySequence_QNAME = new QName("", "ps");
@XmlElementDecl(namespace = "", name = "Root")
public JAXBElement<Root> createRoot(Root value) {
return new JAXBElement<>(ROOT_QNAME, Root.class, null, value);
}
@XmlElementDecl(namespace = "", name = "ps", scope = Property.class)
public JAXBElement<PropertySequence> createPropertySequence(PropertySequence value) {
return new JAXBElement<>(PropertySequence_QNAME, PropertySequence.class, Property.class, value);
}
}
简单的例子:
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.File;
public class JaxbApp {
public static void main(String[] args) throws Exception {
File xmlFile = new File("./resource/test.xml").getAbsoluteFile();
JAXBContext context = JAXBContext.newInstance(Root.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
JAXBElement<Root> root = (JAXBElement<Root>) unmarshaller.unmarshal(xmlFile);
System.out.println(root.getValue());
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(root, System.out);
}
}
打印模型:
RootType{ps=[Property{content=HAS CONCEPT MOD, name='0040A010', vt='8'}
Property{content=CODE, name='0040A040', vt='8'}
Property{content=Property{content=121049, name='00080100', vt='8'}
Property{content=DCM, name='00080102', vt='8'}
Property{content=Language of Content Item and Descendants, name='00080104', vt='8'}
, name='0040A043', vt='8'}
Property{content=Property{content=eng, name='00080100', vt='8'}
Property{content=ISO639_2, name='00080102', vt='8'}
Property{content=English, name='00080104', vt='8'}
, name='0040A168', vt='8'}
, Property{content=HAS OBS CONTEXT, name='0040A010', vt='8'}
Property{content=CODE, name='0040A040', vt='8'}
Property{content=Property{content=121005, name='00080100', vt='8'}
Property{content=DCM, name='00080102', vt='8'}
Property{content=Observer Type, name='00080104', vt='8'}
, name='0040A043', vt='8'}
Property{content=Property{content=121006, name='00080100', vt='8'}
Property{content=DCM, name='00080102', vt='8'}
Property{content=Person, name='00080104', vt='8'}
, name='0040A168', vt='8'}
, Property{content=HAS OBS CONTEXT, name='0040A010', vt='8'}
Property{content=PNAME, name='0040A040', vt='8'}
Property{content=Property{content=121008, name='00080100', vt='8'}
Property{content=DCM, name='00080102', vt='8'}
Property{content=Person Observer Name, name='00080104', vt='8'}
, name='0040A043', vt='8'}
Property{content=IMAGE, name='0040A123', vt='8'}
, Property{content=Property{content=1.2.840.10008.5.1.4.1.1.4, name='00081150', vt='8'}
Property{content=1.3.6.1.4.1.5962.99.1.3923360762.207819601.1541521685498.13.0
, name='00081155', vt='8'}
Property{content=Property{content=1.2.840.10008.5.1.4.1.1.11.1, name='00081150', vt='8'}
Property{content=1.2.840.114356.2019.12.115.113.18.116.1508.6
, name='00081155', vt='8'}
, name='00081199', vt='8'}
Property{content=GEIIS_IW, name='00750010', vt='8'}
Property{content=1, name='007510A1', vt='8'}
, name='00081199', vt='8'}
Property{content=CONTAINS, name='0040A010', vt='8'}
Property{content=IMAGE, name='0040A040', vt='8'}
]}
XmlMixed 和 XmlAnyElement
它会打印空根,因为反序列化对于您的映射无法正常工作,并且根对象为空(propertySequence
为 null
)。您需要更新 POJO
映射。使用 @XmlAnyElement
代替 @XmlElementRef
注释。进行一些更改后的模型可能如下所示:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "Root")
class Root {
@XmlElement(required = true, name = "ps")
protected List<PropertySequence> propertySequence;
// getters, setters, toString
}
@XmlAccessorType(XmlAccessType.FIELD)
class PropertySequence {
@XmlElement(name = "p")
protected List<Property> property;
// getters, setters, toString
}
@XmlAccessorType(XmlAccessType.FIELD)
class Property {
@XmlAttribute(name = "name", required = true)
protected String name;
@XmlAttribute(name = "vt", required = true)
protected Integer vt;
@XmlMixed
@XmlAnyElement
protected List<Object> value;
// getters, setters, toString
}
下面的代码:
import javax.xml.bind.JAXBContext;
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.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlMixed;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class JaxbApp {
public static void main(String[] args) throws Exception {
File xmlFile = new File("./resource/test.xml").getAbsoluteFile();
JAXBContext context = JAXBContext.newInstance(Root.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
Root root = (Root) unmarshaller.unmarshal(xmlFile);
System.out.println(root);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(root, System.out);
}
}
打印对象:
Root{propertySequence=[PropertySequence{property=[Property{name='0040A010', vt=8, value=[HAS CONCEPT MOD]}, Property{name='0040A040', vt=8, value=[CODE]}, Property{name='0040A043', vt=8, value=[
, [ps: null],
]}, Property{name='0040A168', vt=8, value=[
, [ps: null],
]}]}, PropertySequence{property=[Property{name='0040A010', vt=8, value=[HAS OBS CONTEXT]}, Property{name='0040A040', vt=8, value=[CODE]}, Property{name='0040A043', vt=8, value=[
, [ps: null],
]}, Property{name='0040A168', vt=8, value=[
, [ps: null],
]}]}, PropertySequence{property=[Property{name='0040A010', vt=8, value=[HAS OBS CONTEXT]}, Property{name='0040A040', vt=8, value=[PNAME]}, Property{name='0040A043', vt=8, value=[
, [ps: null],
]}, Property{name='0040A123', vt=8, value=[IMAGE]}]}, PropertySequence{property=[Property{name='00081199', vt=8, value=[
, [ps: null],
]}, Property{name='0040A010', vt=8, value=[CONTAINS]}, Property{name='0040A040', vt=8, value=[IMAGE]}]}]}
和XML
:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Root>
<ps>
<p name="0040A010" vt="8">HAS CONCEPT MOD</p>
<p name="0040A040" vt="8">CODE</p>
<p name="0040A043" vt="8">
<ps>
<p name="00080100" vt="8">121049</p>
<p name="00080102" vt="8">DCM</p>
<p name="00080104" vt="8">Language of Content Item and Descendants</p>
</ps>
</p>
<p name="0040A168" vt="8">
<ps>
<p name="00080100" vt="8">eng</p>
<p name="00080102" vt="8">ISO639_2</p>
<p name="00080104" vt="8">English</p>
</ps>
</p>
</ps>
<ps>
<p name="0040A010" vt="8">HAS OBS CONTEXT</p>
<p name="0040A040" vt="8">CODE</p>
<p name="0040A043" vt="8">
<ps>
<p name="00080100" vt="8">121005</p>
<p name="00080102" vt="8">DCM</p>
<p name="00080104" vt="8">Observer Type</p>
</ps>
</p>
<p name="0040A168" vt="8">
<ps>
<p name="00080100" vt="8">121006</p>
<p name="00080102" vt="8">DCM</p>
<p name="00080104" vt="8">Person</p>
</ps>
</p>
</ps>
<ps>
<p name="0040A010" vt="8">HAS OBS CONTEXT</p>
<p name="0040A040" vt="8">PNAME</p>
<p name="0040A043" vt="8">
<ps>
<p name="00080100" vt="8">121008</p>
<p name="00080102" vt="8">DCM</p>
<p name="00080104" vt="8">Person Observer Name</p>
</ps>
</p>
<p name="0040A123" vt="8">IMAGE</p>
</ps>
<ps>
<p name="00081199" vt="8">
<ps>
<p name="00081150" vt="8">1.2.840.10008.5.1.4.1.1.4</p>
<p name="00081155" vt="8">1.3.6.1.4.1.5962.99.1.3923360762.207819601.1541521685498.13.0
</p>
<p name="00081199" vt="8">
<ps>
<p name="00081150" vt="8">1.2.840.10008.5.1.4.1.1.11.1</p>
<p name="00081155" vt="8">1.2.840.114356.2019.12.115.113.18.116.1508.6
</p>
</ps>
</p>
<p name="00750010" vt="8">GEIIS_IW</p>
<p name="007510A1" vt="8">1</p>
</ps>
</p>
<p name="0040A010" vt="8">CONTAINS</p>
<p name="0040A040" vt="8">IMAGE</p>
</ps>
</Root>
关于java - 使用混合类型时编码 XML 没有子级,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55313978/