我试图解组DICOM Sequence VR type,该Content Sequence作为XML CLOB存储在数据库中。按照标准,序列可以包含属性以及子级序列。供参考的示例是属性。
结果,我在我的JAXB DTO中使用@XmlMixed
来处理child属性也可能是序列的情况。但是,在对未编组的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>
以下是用于映射绑定上述结构的类:
@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/>
答案 0 :(得分:1)
即使使用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'}
]}
它打印出空的根目录,因为反序列化不适用于您的映射,并且根目录对象为空(propertySequence
为null
)。您需要更新POJO
映射。相反,对于@XmlElementRef
注释,请使用@XmlAnyElement
。进行少量更改后的模型如下所示:
@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>