当前位置: 首页 > 面试题库 >

Java / JAXB:基于属性将XML解组到特定子类

宋经业
2023-03-14
问题内容

是否可以使用JAXB根据xml的属性将xml解组到特定的Java类?

<shapes>
  <shape type="square" points="4" square-specific-attribute="foo" />
  <shape type="triangle" points="3" triangle-specific-attribute="bar" />
</shapes>

我想要一个包含三角形和正方形的Shape对象的列表,每个对象都有自己的特定于形状的属性。IE浏览器:

abstract class Shape {
    int points;
    //...etc
}

class Square extends Shape {
    String square-specific-attribute;
    //...etc
}

class Triangle extends Shape {
    String triangle-specific-attribute;
    //...etc
}

我目前只是将所有属性都放在一个大的“ Shape”类中,这并不理想。

如果形状已正确命名为xml元素,则可以使它正常工作,但是不幸的是,我无法控制要检索的xml。

谢谢!


问题答案:

JAXB是一个规范,特定的实现将提供扩展点来执行此类操作。如果使用的是EclipseLink
JAXB(MOXy)
,则可以如下修改Shape类:

import javax.xml.bind.annotation.XmlAttribute;
import org.eclipse.persistence.oxm.annotations.XmlCustomizer;

@XmlCustomizer(ShapeCustomizer.class)
public abstract class Shape {

    int points;

    @XmlAttribute
    public int getPoints() {
        return points;
    }

    public void setPoints(int points) {
        this.points = points;
    }

}

然后使用MOXy @XMLCustomizer,您可以访问InheritancePolicy,并将类指示符字段从“ @xsi:type”更改为“
type”:

import org.eclipse.persistence.config.DescriptorCustomizer;
import org.eclipse.persistence.descriptors.ClassDescriptor;

public class ShapeCustomizer implements DescriptorCustomizer {

    @Override
    public void customize(ClassDescriptor descriptor) throws Exception {
        descriptor.getInheritancePolicy().setClassIndicatorFieldName("@type");
    }
}

您将需要确保在模型类(Shape,Square等)的模型类中包含一个jaxb.properties文件,并使用以下条目指定EclipseLink MOXy
JAXB实现:

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

下面是其余的模型类:

形状

import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Shapes {

    private List<Shape> shape = new ArrayList<Shape>();;

    public List<Shape> getShape() {
        return shape;
    }

    public void setShape(List<Shape> shape) {
        this.shape = shape;
    }

}

广场

import javax.xml.bind.annotation.XmlAttribute;

public class Square extends Shape {
    private String squareSpecificAttribute;

    @XmlAttribute(name="square-specific-attribute")
    public String getSquareSpecificAttribute() {
        return squareSpecificAttribute;
    }

    public void setSquareSpecificAttribute(String s) {
        this.squareSpecificAttribute = s;
    }

}

三角形

import javax.xml.bind.annotation.XmlAttribute;

public class Triangle extends Shape {
    private String triangleSpecificAttribute;

    @XmlAttribute(name="triangle-specific-attribute")
    public String getTriangleSpecificAttribute() {
        return triangleSpecificAttribute;
    }

    public void setTriangleSpecificAttribute(String t) {
        this.triangleSpecificAttribute = t;
    }

}

下面是一个演示程序,用于检查一切是否正常:

import java.io.StringReader;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jaxbContext = JAXBContext.newInstance(Shapes.class, Triangle.class, Square.class);

        StringReader xml = new StringReader("<shapes><shape square-specific-attribute='square stuff' type='square'><points>4</points></shape><shape triangle-specific-attribute='triangle stuff' type='triangle'><points>3</points></shape></shapes>");
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        Shapes root = (Shapes) unmarshaller.unmarshal(xml);

        Marshaller marshaller = jaxbContext.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(root, System.out);
    }
}

我希望这有帮助。

有关EclipseLink MOXy的更多信息,请参见:

  • http://www.eclipse.org/eclipselink/moxy.php

编辑

在EclipseLink 2.2中,我们使它更易于配置,请查看以下文章以获取更多信息:

  • http://bdoughan.blogspot.com/2010/11/jaxb-and-inheritance-moxy-extension.html


 类似资料:
  • 问题内容: 有一个丑陋的XML文件必须解组: 产生的Java对象应为: 这个问题的答案非常接近,但我不知道最终的解决方案。 问题答案: 怎么样? 介绍一个称为选项的通用超类: 然后在带有选项列表的类(在本示例中为Configuration)上,在该属性上指定一个@XmlJavaTypeAdapter: XmlAdapter看起来像这样: AdaptedOptions看起来像:

  • 我有一个来自REST API的XML响应,如下所示: 我知道如何使用jaxb获取xml元素值,即“XYZ”,并绑定到bean。但我被困在知道如何获取资源的价值(即https://www.cyz.com),单位(“PH”),href(“ww.com”),div?内xmlns的值,然后将该值映射到对象属性。请帮助我。

  • 问题内容: 我发现很多文章描述了如何将XML元素序列编组到HashMap,只要它们在“父”元素内。但是,我不希望它直接与root元素下的孩子一起工作! 选项1-运作: 选项2 -难道 不 工作: 检查: 检查: CheckMapType: ChecksAdapter: 这是(一些虚拟测试行)我如何生成类/调用解组的方法: 关于如何使选项2起作用的任何想法吗?当使用列表而不是Map时它可以工作,但是

  • 我有一个像这样的xml结构 我需要选择ClassX节点,并在包含constname1(即variable1)AttAttribute的值中 这起作用了。但是,我需要做如下操作,而不是在循环中混合文本 这是我不对的 然而下面是正确的 但我希望将选择范围限制为classX的节点

  • 我从一个xml模式生成java类,对于一个复杂类型,我希望jaxb使用一个现有的类,我有一个外部绑定定制文件。自定义类被解组为正确的,除了该类型的单个属性,该属性从未在java类中填充。 下面是类型/类问题的演示。 模式中定义的内容是: 读取匹配xml文件的代码段是: 在这个xml中阅读: 使用JAXB生成的Thing类(不使用自定义xjb),输出符合预期: 使用只有getters的自定义Thin

  • 我试图将子类属性绑定到GridViewColumn。我有一个母类M1和三个不同的子类S1、S2和S3。GridViewColumn由类M1的对象填充。我希望将S2的一个属性绑定到这个GridViewColumn的头,而M1中没有实现这个属性。 有人能给我解释一下怎么做吗?