我有一个巨大的QuickBooks SDK .XSD模式文件,它定义了我可以从QuickBooks发送/接收的XML请求/响应。
我想要能够轻松地从这些.XSD文件生成Java类,然后将XML转换为Java对象,并将Java对象转换为XML。
有没有一种简单的方法可以做到这一点……?
理想情况下,它不需要在运行时使用除基本Java发行版之外的任何库。但是我可以灵活处理……
进一步阐述上面的“使用JAXB”评论,
在Windows中使用以下命令:
"%java_home%\bin\xjc" -p [你的命名空间] [xsd文件].xsd
例如,
"%java_home%\bin\xjc" -p com.mycompany.quickbooks.obj quickbooks.xsd
稍等片刻,如果您有一个格式良好的XSD文件,则会得到一些格式良好的Java类。
//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
...
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'.]
最简单的方式是使用命令行。只需在您的.xsd文件目录中键入命令:
xjc myFile.xsd.
因此,Java将生成所有的Pojos。
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将在编译时找到它们。No XSD files found. Please check your plugin configuration.
- zygimantusXMLBeans可以实现这个功能,具体使用"scomp"命令。
编辑:XMLBeans已经停止开发,请查看此stackoverflow帖子了解更多信息。
如果您不介意使用外部库,我过去使用Castor来完成这项任务。
JAXB的限制。
我曾经使用过JAXB,我认为它是处理XML和Java对象之间数据的好方法。其中积极的方面是它已被证明在运行时控制数据的性能更好。通过良好的工具或脚本使用,可以省去很多编码工作。
我发现配置部分并不是一项易于解决的任务,我花费了几个小时来搭建开发环境。
然而,由于我遇到了一个愚蠢的限制,我放弃了这个解决方案。我的XML模式定义(XSD)具有名为“value”的属性/元素,并且我必须按照该XSD使用它。这个非常小的约束迫使我的绑定步骤XJC失败,并出现错误“属性'Value'已经被使用。”
这是由于JAXB实现造成的,绑定过程尝试通过将一些属性添加到每个类中来创建Java对象,其中一个属性是值属性。当它处理我的XSD时,它抱怨已经有一个具有相同名称的属性。