引言:
Smooks是一个开源的Java框架,用于处理“数据事件流”。它常常被认为是一个转换框架并以此被用于好几个产品和项目中,包括JBoss ESB(以及其它ESB)。然而究其核心,Smooks未提及“转换”或者其它相关的词汇。它的应用远不只这一点!
Smooks 是一款基于 LGPL 协议的开源 Java 框架,主要用于处理 XML 与 non-XML 格式 ( 包括 CSV,EDI,Java) 之间的转换。Smooks 于 2008 年 5 月发布 v1.0,目前最新的版本已是 v1.3.1。正如 Smooks 开发人员所言,“Smooks …让操作 XML, EDI,XML,CSV 变得更简单”。
实际上,我们通常将 Smooks 看做是一个 XML 到 non-XML 格式的“数据转换引擎”,然而在 Smooks 的核心实现中,本质上是为 XML, CSV, EDI 和 Java 等数据源提供了一个事件流(Event Stream),对数据源的处理其实可以看做是针对此输入数据流的一个个逻辑事件处理。因此,Smooks 的核心其实是一个“结构化数据事件流处理器”。
Smooks:
- 多源数据格式:“轻易”地消费诸多流行的数据格式,包括XML,EDI,CSV,JSON和Java(是的,你可以以一种声明性的方式完成java到java的转换)。
- 转换:利用诸多选项消费由数据源产生的事件流,产生其它格式的结果(即,对源进行“转换”)。这包括能在过滤源数据流时对Smooks所捕获的数据模型应用FreeMarker和XSL模板。鉴于这些模板资源能被运用于源数据事件流内部的事件,因此它们能被用来执行“基于片断的转换(fragment based transforms)”。这意味着Smooks能被用于对数据源的片断执行转换,而不仅限于将数据源作为一个整体来施行转换。
- Java绑定:以一种标准方式由所支持的数据格式(即不仅限于XML)创建和生成Java对象模型/图。由EDI数据源 生成某对象模型的配置与由XML数据源或JSON数据源生成对象模型所进行的配置几乎一模一样。唯一区别在于绑定配置的“事件选择器(event selector)”取值不同。
- 大型消息处理:Smooks支持多种处理大型消息(GBs)的方式,它是通过基于SAX的过滤器完成的。由于综合了 基于片断转换、Java绑定,以及使用节点模型混合DOM和SAX模型所带来的能力,Smooks可以使用较低的内存空间处理大型消息。这些能力允许你执 行直接的1对1转换,同时也支持对大型消息数据流执行1对多的分解、转换和路由。
- 消息修饰:使用数据库数据修饰消息。这可以按片断来完成,即你可以按片断来管理在一个片断上的修饰。与此相关的一个用例是一个包含了消费者ID列表的消息在发往另一个流程前需要从数据库提取消费者地址和概要数据来丰富。
- 基于可扩展XSD的配置模型:从Smooks v1.1开始,你可以用自己的可重用定制访问者逻辑配置模型来扩展Smooks XSD配置名字空间。创建这些定制配置扩展只是一项简单的配置工作,这个工作极大的增进了这些重用组件的可用性。所有的现有Smooks预置组件都利用了这一工具。
Java-to-XML实例:
工具:Eclipse,Smooks
这里采用的是Smooks自带的java-to-xml实例(example文件夹下):
首先,需要做的是在Eclipse中安装Smooks插件。
- 打开Eclipse,点击【Help】-【Install New SoftWare...】-【add】: Name只可以随意设置,Location设置访问【http://download.jboss.org/jbosstools/updates/】,自己选择要用的版本,我这里使用的是【http://download.jboss.org/jbosstools/updates/JBossTools-3.1.1.GA/】
- 设置成功后,选择【Data Services】-【Smooks Tools】,点击【next】,完成安装
然后,编写.xml文件,新建xml源文件夹
Orders.xml
1 <?xml version="1.0" encoding="UTF-8"?>
2 <order>
3 <header>
4 <date>Wed Nov 15 13:45:28</date>
5 <customer number = "123321">Fx</customer>
6 </header>
7 <order-items>
8 <order-item>
9 <product>111</product>
10 <quantity>2</quantity>
11 <price>100</price>
12 </order-item>
13 <order-item>
14 <product>222</product>
15 <quantity>3</quantity>
16 <price>200</price>
17 </order-item>
18 </order-items>
19 </order>
接下里,编写目标Java文件:
Header.java
1 package com.fx.java; 2 3 public class Header { 4 private String date; 5 private String customerNumber; 6 private String customerName; 7 8 public Header(){ 9 date = null; 10 customerNumber = null; 11 customerName = null; 12 } 13 14 public Header(String data, String customerNumber, String customerName) { 15 this.date = data; 16 this.customerNumber = customerNumber; 17 this.customerName = customerName; 18 } 19 20 public String getDate() { 21 return date; 22 } 23 24 public void setDate(String date) { 25 this.date = date; 26 } 27 28 public String getCustomerNumber() { 29 return customerNumber; 30 } 31 32 public void setCustomerNumber(String customerNumber) { 33 this.customerNumber = customerNumber; 34 } 35 36 public String getCustomerName() { 37 return customerName; 38 } 39 40 public void setCustomerName(String customerName) { 41 this.customerName = customerName; 42 } 43 44 }
OrderItem.java
1 package com.fx.java; 2 3 public class OrderItem { 4 5 private String productId; 6 private String quantity; 7 private String price; 8 9 public OrderItem() { 10 productId = null; 11 quantity = null; 12 price = null; 13 } 14 15 public OrderItem(String productId, String quantity, String price) { 16 this.productId = productId; 17 this.quantity = quantity; 18 this.price = price; 19 } 20 21 public String getProductId() { 22 return productId; 23 } 24 25 public void setProductId(String productId) { 26 this.productId = productId; 27 } 28 29 public String getQuantity() { 30 return quantity; 31 } 32 33 public void setQuantity(String quantity) { 34 this.quantity = quantity; 35 } 36 37 public String getPrice() { 38 return price; 39 } 40 41 public void setPrice(String price) { 42 this.price = price; 43 } 44 45 }
Order.java
1 package com.fx.java; 2 3 import java.util.Vector; 4 5 public class Order { 6 public Header header; 7 public Vector<OrderItem> orderItems; 8 9 public Order(){ 10 header = new Header(); 11 orderItems = new Vector<OrderItem>(); 12 } 13 14 public void setHeader(Header header) { 15 this.header = header; 16 } 17 18 public void setOrderItems(OrderItem orderItems) { 19 this.orderItems.add(orderItems); 20 } 21 22 }
接下来,进行作重要的一步:配置Smooks完成xml到 Java对象的映射:
新建一个 Smooks 配置文件:File > New > Smooks > Smooks Configuration File,选择刚才创建的 Java Project 的 src 文件夹作为 Smooks 配置文件的父目录,保留缺省的文件名 smooks-config.xml,单击 Finish 生成初始的配置文件。此时在 Smooks Processing 编辑器中只有一个 Input Task 图标。
单击 Input Task 图标,则可以看到 Smooks input reader 的属性配置界面。由于我们希望完成从 XML 到 Java 的绑定,因此在 Input Type 的下拉菜单中选择“Input Type”为 XML。接下来,在配置界面右侧的 Input Data 中单击 Add 将源 XML 文件添加到项目中。Smooks 会自动解析此 XML 文件并在 Input Model View 中列出其数据模型。
在完成了源数据导入之后,我们要开始配置 Java 绑定。将鼠标移至 Input Task 的蓝色箭头右侧,将会有一个绿色加号(+)出现,单击此加号并选择出现的提示“Java 映射;为了将开发的 Java 类导入 Smooks 配置,在 Selected Task Details 配置框中空白处单击鼠标右键,选择 Add > Java Class,将上文中开发的 Header,OrderItem 以及 Order 类导入。然后就可以非常方便的使用拖曳的方式在左边的 XML 数据模型和右边的 Java 类和成员变量之间建立映射关系,最后的结果如下图所示:
xml表现形式为:
smooks-config.xml
1 <?xml version="1.0" encoding="ASCII"?><smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.1.xsd" xmlns:jb="http://www.milyn.org/xsd/smooks/javabean-1.2.xsd"> 2 <params> 3 <param name="stream.filter.type">SAX</param> 4 <param name="inputType">input.xml</param> 5 <param name="input.xml" type="input.type.actived">Workspace://smooks xml-to-java/xml/Orders.xml</param> 6 </params> 7 <jb:bean beanId="Header" class="com.fx.java.Header" createOnElement="/order/header"> 8 <jb:value data="/order/header/customer" property="customerName"/> 9 <jb:value data="/order/header/customer/@number" property="customerNumber"/> 10 <jb:value data="/order/header/date" property="date"/> 11 </jb:bean> 12 <jb:bean beanId="OrderItem" class="com.fx.java.OrderItem" createOnElement="/order/order-items/order-item"> 13 <jb:value data="/order/order-items/order-item/price" property="price"/> 14 <jb:value data="/order/order-items/order-item/product" property="productId"/> 15 <jb:value data="/order/order-items/order-item/quantity" property="quantity"/> 16 </jb:bean> 17 <jb:bean beanId="Order" class="com.fx.java.Order" createOnElement="order"/> 18 </smooks-resource-list>
最后,进行测试(要记得导入Smooks所需要的架包,将下载下来的Smooks版本的lib文件夹下的所有架包全部导进来):
TestSmooks.java
1 package com.fx.test; 2 3 import java.io.FileInputStream; 4 import java.io.IOException; 5 import javax.xml.transform.stream.StreamSource; 6 import org.milyn.Smooks; 7 import org.milyn.payload.JavaResult; 8 import org.xml.sax.SAXException; 9 import com.fx.java.Header; 10 import com.fx.java.OrderItem; 11 12 public class TestSmooks { 13 14 public static void main(String[] args) throws IOException, SAXException { 15 Smooks smooks = new Smooks("smooks-config.xml"); 16 JavaResult javaResult = new JavaResult(); 17 18 smooks.filterSource(new StreamSource(new FileInputStream("F:\Users\FANXUAN\JunoWorkSpace\smooks xml-to-java\xml\Orders.xml")), javaResult); 19 Header header = (Header)javaResult.getBean("Header"); 20 OrderItem orderItem = (OrderItem)javaResult.getBean("OrderItem"); 21 22 System.out.println("--->" + header.getCustomerNumber()); 23 System.out.println("--->" + header.getCustomerName()); 24 System.out.println(); 25 System.out.println("--->" + orderItem.getProductId()); 26 System.out.println("--->" + orderItem.getQuantity()); 27 System.out.println("--->" + orderItem.getPrice()); 28 } 29 30 31 }
运行得到结果:
由此,我们完成了xml到java转换的配置和测试!