从.XSD文件生成Java类...?

145

我有一个巨大的QuickBooks SDK .XSD模式文件,它定义了我可以从QuickBooks发送/接收的XML请求/响应。

我想要能够轻松地从这些.XSD文件生成Java类,然后将XML转换为Java对象,并将Java对象转换为XML。

有没有一种简单的方法可以做到这一点……?

理想情况下,它不需要在运行时使用除基本Java发行版之外的任何库。但是我可以灵活处理……

11个回答

134

进一步阐述上面的“使用JAXB”评论,

在Windows中使用以下命令:

"%java_home%\bin\xjc" -p [你的命名空间] [xsd文件].xsd

例如, "%java_home%\bin\xjc" -p com.mycompany.quickbooks.obj quickbooks.xsd

稍等片刻,如果您有一个格式良好的XSD文件,则会得到一些格式良好的Java类。


4
好的,谢谢!如果要生成顶级类而不是封装类,请参考以下链接:https://dev59.com/HmYs5IYBdhLWcg3wDft5。如果导致类名冲突,请参考:https://dev59.com/XmrXa4cB1Zd3GeqPEO95。 - tomorrow

126

JAXB可以完美满足你的需求。它内置于自Java 1.6版本起的JRE/JDK中。


8
很遗憾,从Java 9开始,此功能将不再提供。原因是涉及到的类(特别是com.sun.tools.xjc.*类)将不再通过JDK可用。 - Marco
6
我认为从JDK中移除这个并不会成为一个问题,因为java.net项目(答案中提供了链接)可能会保留。 - stmoebius
3
此处所述,你可以通过命令行参数或手动添加依赖项来在Java 9中添加依赖项。 - Matthias Ronge

45
如果您想在不到5分钟的时间内开始编写Java到XML和XML到Java的代码,请尝试使用Simple XML Serialization。不要花费数小时学习JAXB API。 http://simple.sourceforge.net/download/stream/doc/tutorial/tutorial.php 然而,如果您真的很想学习JAXB,这里有一个很好的教程http://blogs.oracle.com/teera/entry/jaxb_for_simple_java_xml
教程内容:
JAXB用于简单的Java-XML序列化
在Java中有许多方法可以进行XML序列化。如果您想对解析和序列化进行细粒度控制,可以选择SAX、DOM或Stax以获得更好的性能。然而,我经常想做的是将POJO和XML之间进行简单映射。但是,手动创建Java类来执行XML事件解析并不是一件轻松的事情。我最近发现JAXB是一种快速方便的Java-XML映射或序列化。
JAXB包含许多有用的功能,您可以在此处查看参考实现。Kohsuke's Blog也是了解JAXB更多信息的好资源。对于本博客文章,我将向您展示如何使用JAXB进行简单的Java-XML序列化。
POJO到XML
假设我有一个Item Java对象。我想将Item对象序列化为XML格式。首先要做的是使用javax.xml.bind.annotation.*包中的一些XML注释来注释这个POJO。请参见代码清单1中的Item.java。
从代码中可以看出:
- @XmlRootElement(name =“Item”)表示我希望它成为根元素。 - @XmlType(propOrder = {“name”,“price”})指示我希望元素在XML输出中排列的顺序。 - @XmlAttribute(name =“id”,...)表示id是根元素的属性。 - @XmlElement(...)表示我希望价格和名称成为Item内的元素。
我的Item.java已准备就绪。然后,我可以继续创建用于编组Item的JAXB脚本。
//creating Item data object
Item item = new Item();
item.setId(2);
item.setName("Foo");
item.setPrice(200);
.....

JAXBContext context = JAXBContext.newInstance(item.getClass());
Marshaller marshaller = context.createMarshaller();
//I want to save the output file to item.xml
marshaller.marshal(item, new FileWriter("item.xml"));

请查看完整的代码清单,请参见代码清单2 main.java。输出的代码清单3 item.xml文件已创建,如下所示:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns1:item ns1:id="2" xmlns:ns1="http://blogs.sun.com/teera/ns/item">
  <ns1:itemName>Foo</ns1:itemName>
  <ns1:price>200</ns1:price>
</ns1:item>

很容易吧?你可以通过简单更改marshal(...)方法的参数,将输出XML作为文本字符串、流、写入器、内容处理器等进行传输。

...
JAXBContext context = JAXBContext.newInstance(item.getClass());
Marshaller marshaller = context.createMarshaller();
// save xml output to the OutputStream instance
marshaller.marshal(item, <java.io.OutputStream instance>);

...
JAXBContext context = JAXBContext.newInstance(item.getClass());
Marshaller marshaller = context.createMarshaller();
StringWriter sw = new StringWriter();
//save to StringWriter, you can then call sw.toString() to get java.lang.String
marshaller.marshal(item, sw);

XML转POJO

现在我们来反转这个过程。假设我现在有一段XML字符串数据,我想将它转换成Item.java对象。 XML数据(代码清单3)的样子如下:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns1:item ns1:id="2" xmlns:ns1="http://blogs.sun.com/teera/ns/item">
  <ns1:itemName>Bar</ns1:itemName>
  <ns1:price>80</ns1:price>
</ns1:item>

我可以通过以下方式将此XML代码解组为Item对象:

...
ByteArrayInputStream xmlContentBytes = new ByteArrayInputStream (xmlContent.getBytes());
JAXBContext context = JAXBContext.newInstance(Item.getClass());
Unmarshaller unmarshaller = context.createUnmarshaller();
//note: setting schema to null will turn validator off
unmarshaller.setSchema(null);
Object xmlObject = Item.getClass().cast(unmarshaller.unmarshal(xmlContentBytes));
return xmlObject;
...

请查看代码清单2(main.java)获取完整的代码列表。XML源可以以多种形式提供,包括流和文件。唯一的区别是方法参数:

...
unmarshaller.unmarshal(new File("Item.xml")); // reading from file
...
// inputStream is an instance of java.io.InputStream, reading from stream
unmarshaller.unmarshal(inputStream);

使用XML Schema进行验证

这里要提到的最后一件事是,在将输入的XML解组为Java对象之前,使用模式对其进行验证。我创建了一个名为item.xsd的XML模式文件。有关完整代码清单,请参见代码清单4(Item.xsd)。现在我需要做的是注册此模式以进行验证。

...
Schema schema = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI)
.newSchema(new File("Item.xsd"));
unmarshaller.setSchema(schema); //register item.xsd shcema for validation
...

当我尝试将XML数据解组为POJO时,如果输入的XML未符合模式,则会捕获异常。完整的代码清单请参见代码清单5(invalid_item.xml)。
javax.xml.bind.UnmarshalException
- with linked exception:
javax.xml.bind.JAXBException caught: null
[org.xml.sax.SAXParseException: cvc-datatype-valid.1.2.1: 'item1' is
                                not a valid value for 'integer'.]

在这里,我将把'id'属性从整数更改为字符串。
如果XML输入符合模式,则XML数据将成功解组为Item.java对象。

1
这看起来非常有前途,而且对于我需要的东西来说,比像JAXB这样庞大而复杂的东西要简单得多,也更易于使用。不幸的是,我没有看到任何将我的现有.XSD转换为.class文件的方法,这真的是我开始所需要的。有什么办法可以做到这一点吗? - Keith Palmer Jr.
7
很遗憾,包含JAXB教程的博客已经下线。 - Luis C.
我们可以轻松地使用jaxb2-maven-plugin来完成,查看这个教程http://www.journaldev.com/1312/how-to-generate-java-classes-from-xsd-using-xjc-maven-plugin - Pankaj

33
使用Eclipse IDE: -
  1. 将xsd复制到新/现有项目中。
  2. 确保您的类路径中具有所需的JAXB JAR。 您可以从此处下载。
  3. 右键单击xsd文件->生成->JAXB类。

20

最简单的方式是使用命令行。只需在您的.xsd文件目录中键入命令:

xjc myFile.xsd.

因此,Java将生成所有的Pojos。


你可以在这里获取xjc:https://repo1.maven.org/maven2/com/sun/xml/bind/jaxb-ri/4.0.3/jaxb-ri-4.0.3.zip - undefined

19

Maven可以用于此目的,您需要添加一些依赖项并清理应用程序。所有类将自动创建在目标文件夹中。

只需从目标文件夹将它们复制到所需位置,这是我用来从xsd文件创建类的pom.xml

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>jaxb2-maven-plugin</artifactId>

    <executions>
        <execution>
            <goals>
                <goal>xjc</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <schemaDirectory>src/main/webapp/schemas/</schemaDirectory>
    </configuration>
</plugin>
只需将您的xsd文件放置在 src/main/webapp/schemas/ 下,Maven将在编译时找到它们。

1
这个能够和资源目录(src/main/resources/schemas)一起工作吗?因为我一直收到这个错误信息:No XSD files found. Please check your plugin configuration. - zygimantus
在此插件的较新版本中,<schemaDirectory>已被弃用并被<sources>替换(参见https://www.mojohaus.org/jaxb2-maven-plugin/Documentation/v3.1.0/xjc-mojo.html#sources) - Matze

16

现在XMLBeans已经被停用,应该使用什么替代品? - TofuBeer

8

如果您不介意使用外部库,我过去使用Castor来完成这项任务。


如果您使用Castor生成代码,那么在此之后生成的类是否仍然依赖于Caster?或者我可以将这些类移动到一个没有Castor库的机器上,它们仍然可以工作吗? - Keith Palmer Jr.
不,生成的类不依赖于Castor库。 - dave
有没有关于如何使用Castor的好教程?它看起来非常有前途...但是Java可以说不是我的强项。我不确定需要下载哪些Castor文件/包以及如何进行代码生成...有没有适合新手的逐步示例? - Keith Palmer Jr.
请查看此页面以获取有关如何使用Castor SourceGenerator类的文档:http://www.castor.org/sourcegen.html - Marc Novakowski

6

JAXB的限制。

我曾经使用过JAXB,我认为它是处理XML和Java对象之间数据的好方法。其中积极的方面是它已被证明在运行时控制数据的性能更好。通过良好的工具或脚本使用,可以省去很多编码工作。

我发现配置部分并不是一项易于解决的任务,我花费了几个小时来搭建开发环境。

然而,由于我遇到了一个愚蠢的限制,我放弃了这个解决方案。我的XML模式定义(XSD)具有名为“value”的属性/元素,并且我必须按照该XSD使用它。这个非常小的约束迫使我的绑定步骤XJC失败,并出现错误“属性'Value'已经被使用。”

这是由于JAXB实现造成的,绑定过程尝试通过将一些属性添加到每个类中来创建Java对象,其中一个属性是值属性。当它处理我的XSD时,它抱怨已经有一个具有相同名称的属性。


3

众所周知的JAXB

有一个maven插件可以在任何构建阶段为您完成此操作。

您可以通过xsd <-> Java两种方式进行此操作。


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