如何从XSD模式生成简单的XML Java注释对象

25

好的,我在stackoverflow上搜索了有关这个问题的未回答的子主题,因此我希望这个问题能够清楚地指出:

有没有工具可以从xsd模式生成Simple Xml库的注释Java类?

我收到了描述由他人开发的restful web-service返回对象的几个xsd文件,目前我已将这些模式转换为simple-xml注释类。这些类将用于我的Android应用程序。最好自动同步模式中的任何更改,并从中重新生成类。ws团队对这些模式有符合Jackson要求的类的存储库,但我不想使用Jackson - 我正在使用Spring Android,因此我更喜欢使用首选的simple-xml。一定有一些像JAXB的xjc工具一样做到这一点的工具。

如果没有这样的工具,您是否能想到实现生成simple-xml .java文件的脚本时遇到的任何陷阱?也许有值得扩展的工具的提示,只需要定义要生成的注释以及何时生成就可以了吗?

提前感谢您的答案!


你之前有解决过这个问题吗?我也想用一个XSD文件生成Java类,然后在Simple-XML中使用那些类。 - stackoverflowuser2010
3个回答

4
我写了一个库,可以从XSD生成SimpleXML Java注释类。这是链接: https://github.com/yeshodhan/android-jaxb
例如: XML模式
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://person.mickoo.com/"
            targetNamespace="http://person.mickoo.com/" elementFormDefault="qualified">

    <xsd:element name="Person" type="Person"/>

    <xsd:complexType name="Person">
        <xsd:sequence>
            <xsd:element name="FirstName" type="xsd:string" minOccurs="0" />
            <xsd:element name="LastName" type="xsd:string" minOccurs="0" />
            <xsd:element name="Adult" type="xsd:boolean" minOccurs="0" />
            <xsd:element name="Addresses" type="Addresses" minOccurs="0" />
            <xsd:element name="Gender" type="Gender" minOccurs="0" />
            <xsd:element name="Favorite_Fruits" type="Fruits" minOccurs="0" maxOccurs="3"/>
            <xsd:element name="SomeThing_really_whacky-by-the-user" type="xsd:string" minOccurs="0" />
        </xsd:sequence>
        <xsd:attribute name="id" type="xsd:string"/>
    </xsd:complexType>

    <xsd:complexType name="Addresses">
        <xsd:sequence>
            <xsd:element name="Address" type="Address" minOccurs="0" maxOccurs="unbounded"/>
        </xsd:sequence>
    </xsd:complexType>

    <xsd:complexType name="Address">
        <xsd:sequence>
            <xsd:element name="Line1" type="xsd:string" minOccurs="0" />
            <xsd:element name="Line2" type="xsd:string" minOccurs="0" />
            <xsd:element name="City" type="xsd:string" minOccurs="0" />
            <xsd:element name="State" type="xsd:string" minOccurs="0" />
            <xsd:element name="Country" type="xsd:string" minOccurs="1" />
            <xsd:element name="PostalCode" type="xsd:string" minOccurs="0" />
        </xsd:sequence>
    </xsd:complexType>

    <xsd:simpleType name="Gender">
        <xsd:restriction base="xsd:string">
            <xsd:enumeration value="MALE"/>
            <xsd:enumeration value="FEMALE"/>
            <xsd:enumeration value="NOT_SPECIFIED"/>
        </xsd:restriction>
    </xsd:simpleType>

    <xsd:simpleType name="Fruits">
        <xsd:restriction base="xsd:string">
            <xsd:enumeration value="Apple"/>
            <xsd:enumeration value="Banana"/>
            <xsd:enumeration value="Mango"/>
            <xsd:enumeration value="Orange"/>
            <xsd:enumeration value="Grapes"/>
            <xsd:enumeration value="Watermelon"/>
            <xsd:enumeration value="Peach"/>
            <xsd:enumeration value="Apricot"/>
            <xsd:enumeration value="Grapefruit"/>
        </xsd:restriction>
    </xsd:simpleType>

</xsd:schema>

生成的Java类

package com.mickoo.person;

import org.simpleframework.xml.Element;
import org.simpleframework.xml.Namespace;
import org.simpleframework.xml.Root;


@Root(name = "Address")
@Namespace(reference = "http://person.mickoo.com/")
public class Address {

    @Element(name = "Line1", required = false)
    private String line1;
    @Element(name = "Line2", required = false)
    private String line2;
    @Element(name = "City", required = false)
    private String city;
    @Element(name = "State", required = false)
    private String state;
    @Element(name = "Country", required = true)
    private String country;
    @Element(name = "PostalCode", required = false)
    private String postalCode;

    public Address() {
    }

    public String getLine1() {
        return line1;
    }

    public void setLine1(String line1) {
        this.line1 = line1;
    }

    public String getLine2() {
        return line2;
    }

    public void setLine2(String line2) {
        this.line2 = line2;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    public String getPostalCode() {
        return postalCode;
    }

    public void setPostalCode(String postalCode) {
        this.postalCode = postalCode;
    }

}

package com.mickoo.person;

import java.util.List;
import org.simpleframework.xml.ElementList;
import org.simpleframework.xml.Namespace;
import org.simpleframework.xml.Root;


@Root(name = "Addresses")
@Namespace(reference = "http://person.mickoo.com/")
public class Addresses {

    @ElementList(name = "Address", entry = "Address", inline = true, required = false)
    private List<Address> address;

    public Addresses() {
    }

    public List<Address> getAddress() {
        return address;
    }

    public void setAddress(List<Address> address) {
        this.address = address;
    }

}

package com.mickoo.person;

import org.simpleframework.xml.Namespace;
import org.simpleframework.xml.Root;

@Root(name = "Fruits")
@Namespace(reference = "http://person.mickoo.com/")
public enum Fruits {

    Apple,
    Banana,
    Mango,
    Orange,
    Grapes,
    Watermelon,
    Peach,
    Apricot,
    Grapefruit;

}

package com.mickoo.person;

import org.simpleframework.xml.Namespace;
import org.simpleframework.xml.Root;

@Root(name = "Gender")
@Namespace(reference = "http://person.mickoo.com/")
public enum GenderEnum {

    MALE(0, "Men are from Mars"),
    FEMALE(1, "Women are from Venus"),
    NOT_SPECIFIED(2, "Can't say anything");
    private final Integer id;
    private final String description;

    private GenderEnum(Integer id, String description) {
        this.id = id;
        this.description = description;
    }

    public Integer id() {
        return id;
    }

    public String description() {
        return description;
    }

}


package com.mickoo.person;

import java.util.List;
import org.simpleframework.xml.Attribute;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.ElementList;
import org.simpleframework.xml.Namespace;
import org.simpleframework.xml.Root;


@Root(name = "Person")
@Namespace(reference = "http://person.mickoo.com/")
public class Person {

    @Element(name = "FirstName", required = false)
    private String firstName;
    @Element(name = "LastName", required = false)
    private String lastName;
    @Element(name = "Adult", required = false)
    private Boolean adult;
    @Element(name = "Addresses", required = false)
    private Addresses addresses;
    @Element(name = "Gender", required = false)
    private GenderEnum gender;
    @ElementList(name = "Favorite_Fruits", entry = "Favorite_Fruits", inline = true, required = false)
    private List<Fruits> favoriteFruits;
    @Element(name = "SomeThing_really_whacky-by-the-user", required = false)
    private String someThingReallyWhackyByTheUser;
    @Attribute(name = "id", required = false)
    private String id;

    public Person() {
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Boolean getAdult() {
        return adult;
    }

    public void setAdult(Boolean adult) {
        this.adult = adult;
    }

    public Addresses getAddresses() {
        return addresses;
    }

    public void setAddresses(Addresses addresses) {
        this.addresses = addresses;
    }

    public GenderEnum getGender() {
        return gender;
    }

    public void setGender(GenderEnum gender) {
        this.gender = gender;
    }

    public List<Fruits> getFavoriteFruits() {
        return favoriteFruits;
    }

    public void setFavoriteFruits(List<Fruits> favoriteFruits) {
        this.favoriteFruits = favoriteFruits;
    }

    public String getSomeThingReallyWhackyByTheUser() {
        return someThingReallyWhackyByTheUser;
    }

    public void setSomeThingReallyWhackyByTheUser(String someThingReallyWhackyByTheUser) {
        this.someThingReallyWhackyByTheUser = someThingReallyWhackyByTheUser;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

}

使用方法

➜  target git:(master) ✗ java -jar android-jaxb-1.0.jar --help
usage: java -jar android-jaxb-1.0.jar [options] your-schema-file.xsd
---------------------------------------------------------------------
 -b,--bindings <arg>      (optional) bindings JSON file
 -d,--destination <arg>   destination directory for generated classes
 -h,--help                Help on usage
 -p,--package <arg>       package name for generated classes. Eg.:
                          com.example.app
 -v,--version             Version
---------------------------------------------------------------------

1
java -jar android-jaxb-1.0.jar -d ... Metadata.xsd 代码生成器已初始化。目标目录:D:\Projects\Android\XsdToSimpleXML [元素/frequencyConfig 最小出现次数:null,最大出现次数:null] 类型为 [null] [序列开始 最小出现次数:1,最大出现次数:1] [元素/frequencyConfig/dateStart 最小出现次数:1,最大出现次数:1] 类型为 [dateTime] 主线程中的异常 "main" java.lang.NullPointerException at com.sun.codemodel.JVar.annotate(JVar.java:188) at com.mickoo.xml.xsd2simplexml.GeneratedClass.addElement(GeneratedClass .java:62) - Peter Barbanyaga
2
你的库为序列生成了许多异常,例如“Exception in thread "main" java.lang.NullPointerException at com.sun.codemodel.JVar.annotate”。为什么会这样? - Peter Barbanyaga
你能把你正在尝试解析的XSD文件发给我吗? - Yeshodhan Kulkarni
我怎样才能理解问题是因为我没有使用JSON描述。使用JSON描述是必要的吗? - Peter Barbanyaga
Yeshodhan,你还在继续开发这个项目吗?我想使用它,但是当我尝试时出现了NullPointerException。 - alicjab
我知道这已经很老了,但是我用它成功地进行了转换,需要注意两点:
  1. 您需要传递目标和包选项。如果您只传递包选项,则生成器将抛出NPE。
  2. 您只能使用简单类型,否则会得到NPE。例如,“xsd:date”不受支持。我手动替换了每个导致NPE的类型。您可以通过查看在NPE之前打印出的最后一个节点,并将其替换为基本类型来确定哪种类型引起了问题。
- Selali Adobor

4
我不认为JAXB可以在Android上使用,因为缺少包要求(见此处),特别是在早期版本的Android API中。相反,您可以通过xjc发送您的XSD并获取JAXB类输出,然后编写脚本将JAXB注释转换为等效的Simple XML注释。这应该正好符合您的要求。
但是,理想情况下,如果您有时间,可以查看xjc的源代码并扩展它,以便能够输出JAXB或Simple注释的类。

0
据我所知,Simple XML 用于创建带注释的类来进行 XML 带/解带。
Java Web Services 框架使用特定绑定:
例如,CXF 支持(除了 JAXB 之外)Aegis、XML Beans 等CXF 数据绑定
Axis2 支持 ADB、XMLBeans 等Axis2 数据绑定
JAX-WS 也是如此
我不知道 Spring WS(但我怀疑他们是否专门支持 Simple)
在我看来,如果你一定需要使用 Simple XML,那么自己创建类似乎是可行的。因为你指出:
I received a couple of xsd files describing the objects returned by a restful web-service 

所以对于一些文件可能是可行的。 我不认为您应该担心Web服务实现者对模式进行的更改,因为如果他们进行更改,您将无论如何需要重新生成客户端部分。 无论如何,一旦部署了Web服务,模式就不会经常更改,否则所有客户端应用程序都将受到影响。
如果您想创建自己的工具,则必须创建一个代码生成器,该生成器将解析xsd文件并为Simple XML创建带注释的类。 这对我来说似乎需要很多努力。
希望这有所帮助


Spring Android Rest Template模块依赖于simple-xml(来源:http://static.springsource.org/spring-android/docs/1.0.x/reference/html/rest-template.html)。 我对Simple专用工具很感兴趣,虽然我知道还有其他选择,但我想使用Spring Android :) 我们的ws团队正在开发一个服务器应用程序,我们希望通过Android客户端访问它。自动化xsd->java意味着少做一些工作。一旦他们更改了某些内容,一些脚本可能会自动重新生成Android客户端应用程序中的对象。 - Dariusz Jędrzejczyk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接