Java 使用混合类型时,封送的XML没有子级

Java 使用混合类型时,封送的XML没有子级,java,xml,jaxb,Java,Xml,Jaxb,我正在尝试解组存储在数据库中的XML CLOB。根据标准,序列可以包含属性以及子序列。引用的一个示例是属性 因此,我在JAXB DTO中使用@XmlMixed来处理子属性也可能是序列的情况。但是,在编组未编组的XML时,结果输出只是根元素,没有子元素 下面是表示上述内容序列的输入XML <Root> <ps> <p name="0040A010" vt="8">HAS CONCEPT MOD</p> <p name="00

我正在尝试解组存储在数据库中的XML CLOB。根据标准,序列可以包含属性以及子序列。引用的一个示例是属性

因此,我在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>
输出

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Root/>

XmlMixed&xmlementref 即使使用
xmlementref
我们也无法将值反序列化为
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);
    }
}
XmlMixed&xmlanyement 它打印空根,因为反序列化不能正确地用于映射,并且根对象为空(
propertySequence
is
null
)。您需要更新
POJO
映射。使用
@xmlanyementref
注释代替
@xmlanyement
。经过少量更改后的模型可能如下所示:

@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
}
打印对象:

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>

具有概念模型

代码

121049

DCM

内容项及其子体的语言

工程

ISO639\U 2

英语

具有OBS上下文

代码

121005

DCM

观察员类型

121006

DCM

具有OBS上下文

PNAME

121008

DCM

观察者姓名

图像

1.2.840.10008.5.1.4.1.1.4

1.3.6.1.4.1.5962.99.1.3923360762.2078119601.1541521685498.13.0

1.2.840.10008.5.1.4.1.1.11.1

1.2.840.114356.2019.12.115.113.18.116.1508.6

GEIS\u IW

1

包含

图像


解组只是为了测试绑定。但是,如果我们看到
System.out
,嵌套序列将显示null-
属性{name='0040A168',vt=8,value=[,[ps:null],]
。如何捕获嵌套序列并递归读取它?
@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'}
]}
@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 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>