JAXB将多个XML元素编组和解组到一个类中并反转

时间:2016-05-10 11:19:54

标签: java xml jaxb marshalling unmarshalling

我正在尝试将以下“attrName”和“attrType”XML-Elements编组并解组为单个类。 (目前我单独读取值并在Java中解组后构造我的对象。)

<wrapper>
    <someOtherElement>xxx</someOtherElement>
    <attrName ref="a">xxx</attrName>
    <attrName ref="b">xxx</attrName>
    <attrName ref="c">xxx</attrName>
    <attrType attrRef="a">xxx</attrType>
    <attrType attrRef="b">xxx</attrType>
    <someOtherElement>xxx</someOtherElement>
</wrapper>

“ref”XML-Attribute用于标识属性,并用作“attrType”XML-Element的引用。但是“attrType”XML-Element是可选的,不能存在。没有“attrName”XML元素的“attrType”XML元素。

我需要生成类的“属性”对象列表:

package example;

public class Attribute {

    private String name;

    private String ref;

    private String type;

    public String  getName() {
        return name;
    }

    public void setName(String name) {
        this.name= name;
    }

    public String  getRef() {
        return ref;
    }

    public void setRef(String ref) {
        this.ref= ref;
    }

    public String  getType() {
        return type;
    }

    public void setType(String type) {
        this.type= type;
    }
}

我已经找到以下关于question的内容。但它并没有帮助我找到解决问题的方法。 问题是找到所有相关的属性名称和类型来构造Java对象。

我会对正确方向的任何提示或建议表示感谢。如果我没有解释任何令人满意的事情,请不要犹豫,因为英语不是我的母语。

  

PS:我知道我可以使用不同的XML结构并轻松解决问题。但这对我来说是不可能的。

2 个答案:

答案 0 :(得分:0)

您的XML文件不遵循任何架构,因此您只能依赖其根元素名称以及格式正确的事实。下面将它映射到通用Wrapper对象,然后处理它以生成Attribute对象列表:

public class JAXBAttribute {

    public static void main(String[] args) throws JAXBException {
        JAXBContext context = JAXBContext.newInstance(new Class[] {Wrapper.class});
        Wrapper wrapper = (Wrapper)context.createUnmarshaller().unmarshal(Thread.currentThread().getContextClassLoader().getResourceAsStream("wrapper.xml"));
        final Map<String,String> attributeTypeMap = new HashMap<String,String>();
        for(final AttributeTypeMapEntry entry : wrapper.getEntryList()) {
            attributeTypeMap.put(entry.getKey(), entry.getValue());
        }
        for(final Attribute a : wrapper.getAttributeObjectList()) {
            a.setType(attributeTypeMap.get(a.getRef()));
        }
        System.out.println(wrapper.getAttributeObjectList());
    }

}

@XmlRootElement(name="wrapper")
@XmlAccessorType(XmlAccessType.NONE)
class Wrapper {

    @XmlElement(name="attrName")
    private List<Attribute> attributeObjectList;

    @XmlElement(name="attrType")
    private List<AttributeTypeMapEntry> entryList;

    public List<Attribute> getAttributeObjectList() {
        return attributeObjectList;
    }

    public List<AttributeTypeMapEntry> getEntryList() {
        return entryList;
    }
}

@XmlAccessorType(XmlAccessType.NONE)  // Only annotated fields will be mapped
class AttributeTypeMapEntry {

    @XmlAttribute(name="attrRef")
    private String key;

    @XmlValue
    private String value;

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return "AttributeTypeMapEntry [key=" + key + ", value=" + value + "]";
    }
}

@XmlAccessorType(XmlAccessType.NONE) // Only annotated fields will be mapped
class Attribute {

    @XmlValue
    private String name;

    private String type;

    @XmlAttribute(name="ref")
    private String ref;

    public String  getName() {
        return name;
    }

    public void setName(String name) {
        this.name= name;
    }

    public String getRef() {
        return ref;
    }

    public void setRef(String ref) {
        this.ref= ref;
    }

    public String  getType() {
        return type;
    }

    public void setType(String type) {
        this.type= type;
    }

    @Override
    public String toString() {
        return "Attribute [name=" + name + ", type=" + type + ", ref=" + ref + "]";
    }
}

答案 1 :(得分:0)

这是同一任务的另一种解决方案。我们的想法是将初始文档转换为直接映射XML格式,同时解析所有引用,然后将生成的XML映射到Java对象。

您的数据的XSLT将是:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="/wrapper">
        <xsl:variable name="root" select="."/>
        <xsl:copy>
            <xsl:for-each select="attrName">
                <xsl:variable name="ref" select="@ref"></xsl:variable>
                <attribute>
                    <name><xsl:value-of select="text()"/></name>
                    <ref><xsl:value-of select="$ref"/></ref>
                    <type><xsl:value-of select="$root/attrType[@attrRef=$ref]/text()"/></type>
                </attribute>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="text()"/>
</xsl:stylesheet>

直接映射XML看起来像:

<?xml version="1.0" encoding="utf-8"?>
<wrapper>
   <attribute>
      <name>xxx</name>
      <ref>a</ref>
      <type>xxx</type>
   </attribute>
   <attribute>
      <name>xxx</name>
      <ref>b</ref>
      <type>xxx</type>
   </attribute>
   <attribute>
      <name>xxx</name>
      <ref>c</ref>
      <type/>
   </attribute>
</wrapper>

带注释的代码如下:

public class JAXBAttribute {

    public static void main(String[] args) throws Exception {
        // Transform initial XML resolving all references, resulting in an straight-to-map XML
        final Transformer t = TransformerFactory.newInstance().newTransformer(
            new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream("wrapper.xsl")));
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        t.transform(
            new StreamSource(Thread.currentThread().getContextClassLoader().getResourceAsStream("wrapper.xml")), 
            new StreamResult(baos));
        // Create Java objects from a straight-to-map XML
        JAXBContext context = JAXBContext.newInstance(new Class[] {Wrapper.class});
        Wrapper wrapper = (Wrapper)context.createUnmarshaller().unmarshal(new ByteArrayInputStream(baos.toByteArray()));
        //
        System.out.println(wrapper.getAttributeObjectList());
    }

}

@XmlRootElement(name="wrapper")
@XmlAccessorType(XmlAccessType.FIELD)
class Wrapper {

    @XmlElement(name="attribute")
    private List<Attribute> attributeObjectList;

    public List<Attribute> getAttributeObjectList() {
        return attributeObjectList;
    }
}

@XmlAccessorType(XmlAccessType.FIELD)
class Attribute {

    private String name;

    private String type;

    private String ref;

    public String  getName() {
        return name;
    }

    public void setName(String name) {
        this.name= name;
    }

    public String getRef() {
        return ref;
    }

    public void setRef(String ref) {
        this.ref= ref;
    }

    public String  getType() {
        return type;
    }

    public void setType(String type) {
        this.type= type;
    }

    @Override
    public String toString() {
        return "Attribute [name=" + name + ", type=" + type + ", ref=" + ref + "]";
    }
}

注意此示例的所有文件都保存在类路径根目录中。