IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  Lotus | WebSphere  >

使用 WebSphere Portlet Factory 构建企业级复合应用

WebSphere Portlet Factory 处理 XML 的方法

developerWorks
文档选项

未显示需要 JavaScript 的文档选项

样例代码


级别: 初级

高 爽 (gaos@cn.ibm.com), 软件工程师, IBM

2008 年 7 月 01 日

数据提供者和消费者是使用 WebSphere Portlet Factory(以下简称 WPF)开发应用的核心模式,符合 Service-Oriented Architecture(SOA)的理念。利用它可以很好地屏蔽后台系统的复杂性和多样性,实现数据层与展现层的分离,提供给开发人员一个松耦合的应用架构。支撑这一模式的核心技术是 XML 。 XML 作为数据提供者和消费者之间统一的数据流形式,Schema 负责描述 XML 的数据结构。

本文旨在分析如何利用 WPF 提供的处理 XML 的手段,包括使用构建器(Builder)和内置 API 两种方式。为开发人员提供帮助和指导。

使用构建器(Builder)处理 XML

模式(Schema)构建器

此构建器用于定义 XML Schema,即 XML 文档的数据结构。同时,提供了验证 XML 的机制。利用模式构建器可以通过两种方式定义 Schema:

  1. 直接以 URL 或文件两种形式引用已经定义完成的 Schema 。例如:http://www.myschemas.org/schemas/schema1.xsd或 file://c:\myschema\schema1.xsd
  2. 在构建起的 模式源 输入框提供描述 Schema 的 XML 文档。

简单模式生成器(Simple Schema Generator)构建器

此构建器可以根据一个已经在模型(Model)中存在的 XML 变量自动生成 Schema 。使用这种方法,可以简化 Schema 的定义。

转换(Transform)构建器

此构建器能够实现将一个模式类型(定义了 Schema)XML 变量的内容复制或合并到另一个模式类型的变量中。其优点在于不需要编写任何 XSLT 或 IXml(WPF 中提供的处理 XML 的 API,会在 使用 API 处理 XML 部分介绍)代码。借助于 转换构建器的功能,可以帮助我们快速实现复合应用(Composite application),将来源于不同系统的数据合并到一个 XML 变量中,从而通过统一、标准的界面展现给用户。

转换 - 排序(Transform-Sort)构建器

此构建器可以对 XML 变量中的元素进行排序。排序后的结果可以直接保存到原始变量或其它 XML 变量。

转换 - 过滤(Transform-Filter)构建器

此构建器可以根据设定的条件过滤 XML 变量中的元素。过滤后的结果可以直接保存到原始变量或其它 XML 变量。

样例介绍

下面将通过一个例子,帮助大家深入理解以上介绍的构建器如何处理 XML 。

应用场景描述:我们开发一个待办信息查询的应用,使用户在一个界面中,可以获知需要他处理的所有工作。在实际的应用环境里,待办信息往往分散在不同的应用系统中,比如:数据库、Domino、ERP 等等。用户需要不停地在系统间进行切换以获取信息。在我们开发的应用中,将采用复合应用的方式。用户在一个标准化的统一界面中,可以快速访问到来自多个系统同一性质的数据和信息。为了便于代码共享,在我们的例子中使用 XML 和 Excel 作为后台数据源。

  1. 在 WPF 项目(已有或新建)中创建一个空的模型。然后,添加一个类型为变量的构建器。在构建器定义界面中,选择类型为 XML ;将我们事先准备好的 XML 格式的待办信息文档拷贝到初始值输入框中。

    图 1. 定义存储 XML 格式待办信息的变量
    图 1. 定义存储 XML 格式待办信息的变量

  2. 添加类型为 简单模式生成器 的构建器。样本数据选择之前定义的 XML 变量。

    图 2. 生成待办信息 XML 的 Schema
    图 2. 生成待办信息 XML 的 Schema

  3. 切换到模型的 Web 应用程序树 视图。在 Schema 部分,我们可以发现构建器已经根据 XML 变量生成了相应的 Schema 。

    图 3. Schema 的 XML 描述文档
    图 3. Schema 的 XML 描述文档

  4. 把变量的类型由最初的 XML 改为 Schema 所定义的模式类型。

    图 4. 修改变量类型
    图 4. 修改变量类型

  5. 在模型中添加为Excel 导入的构建器。把存储在 Excel 表格中的待办信息数据导入模型。Excel 导入构建器会根据提供的数据自动生成 Schema 。

    图 5. 在导入文件输入框提供 Excel 文件所在的路径
    图 5. 在导入文件输入框提供 Excel 文件所在的路径

  6. 自此,XML 和 Excel 中的数据已经被先后注入模型。接下来,为了创建一个新的 XML 变量用于存储从两个数据源合并后的结果,我们首先需要定义一个描述统一代办信息的 Schema 。在模型中添加类型为模式的构建器。在模式源输入框中提供描述 Schema 的 XML 文档。建议使用专业创建 XML Schema 的工具,如 XMLSpy 。然后把创建好 Schema 文档拷贝到输入框中。

    图 6. 定义描述统一待办信息的 Schema
    图 6. 定义描述统一待办信息的 Schema

  7. 添加一个新的变量,类型为统一待办信息 Schema 。

    图 7. 变量用于存储合并后的待办信息
    图 7. 变量用于存储合并后的待办信息

  8. 下面的部分是构建此应用的核心部分,涉及到如何对数据进行合并的操作。在模型中添加一个类型为转换的构建器。此构建器负责将源模式类型的 XML 变量(全部或部分)复制到目标模式类型的 XML 变量。第一步先把源数据为 XML 的待办信息拷贝到之前定义的统一待办信息 XML 变量。开始拷贝之前,可以指定是否清空目标变量。

    图 8. XML 变量复制
    图 8. XML 变量复制

    下图表示了目标模式与源模式节点间的映射关系。在统一待办信息 Schema 中未定义 category 元素,故存储在 XML 数据中的 category 信息会被放弃。



    图 9. 映射关系
    图 9. 映射关系

  9. 接下来,拷贝存储在 Excel 表格中的数据。方法同上。

    图 10. 注意节点之间的映射关系
    图 10. 注意节点之间的映射关系

  10. 在模型中添加一个类型为 操作列表 的构建器,用于执行数据拷贝的操作。方法由转换构建器产生,名称形式为:<TransformName>CallCopy 。

    图 11. 执行拷贝操作
    图 11. 执行拷贝操作

  11. 通过两次调用 转换 构建器,之前分散存储在 XML 和 Excel 中的数据,已经合并到一个 XML 变量中。调用 视图和表单 构建器,生成显示待办信息列表的页面。

    图 12. 负责展现的构建器
    图 12. 负责展现的构建器

  12. 运行模型。我们可以看到存储在多个系统中的待办信息实现了统一展现。

    图 13. 待办信息列表
    图 13. 待办信息列表

  13. 为了方便用户查看,可以按照优先级对待办信息排序。在模型中添加变换 - 排序构建器。指定待排序的 XML 变量,设定 priority 作为排序条件。比较类型分为四种:区分大小写的字符串、不区分大小写、数字和日期。

    图 14. 按照优先级对待办信息排序
    图 14. 按照优先级对待办信息排序

  14. 修改 操作列表 构建器,加入执行排序的方法。方法由变换 - 排序构建器产生,名称形式为:<builderName>CallSort

    图 15. 执行排序操作
    图 15. 执行排序操作

  15. 运行模型。可以看到待办信息按照优先级别进行了排序。

    图 16. 按优先级排序后的待办信息列表
    图 16. 按优先级排序后的待办信息列表

  16. 同时,我们也可以对待办信息进行过滤。在模型中添加类型为变换 - 过滤的构建器,提供待过滤的 XML 变量,指定过滤条件:状态为进行中的待办。

    图 17. 筛选状态为进行中的待办信息
    图 17. 筛选状态为进行中的待办信息

  17. 修改 操作列表 构建器,加入执行过滤操作的方法。方法由变换 - 过滤构建器产生,名称形式为:<builderName>CallFilter

    图 18. 执行过滤操作
    图 18. 执行过滤操作

  18. 运行模型。界面只显示满足条件的数据。

    图 19. 显示状态为进行中的待办信息
    图 19. 显示状态为进行中的待办信息





回页首


使用 API 处理 XML

除了以上部分介绍的标准化构建器,WPF 同时提供处理 XML 的 API 。适用于在使用构建器无法满足应用要求的情况,比如:当源数据或目标数据的 XML Schema 结构比较复杂,差异比较大时,直接用转换构建器的方法进行数据复制比较困难,无法指定节点之间的映射关系。 API 的主要的接口是 com.bowstreet.util.IXml,采用标准的 DOM(Document Object Model)方式处理 XML 。可以实现插入 XML 元素(Element)、获取文本(Text)、设置属性(Attribute)等常规的 XML 操作。

样例介绍

应用场景:某 ERP 系统提供 XML 文档,其中包含财务系统中的数据。需要借助图形或仪表盘等形式在门户中进行展现。

清单 1 中的 XML 用于描述财务范畴的台帐(Voucher)信息;清单 2 中的 XML 描述人员信息。在台帐 XML 中引用了人员代码,通过personnel_id属性与人员 XML 进行关联。


清单 1. 台帐信息 XML 片段
                
 <vouchers> 
	…
	 <voucher id="00001"> 
		 <voucher_head> 
			 <company> 技术中心 </company> 
			 <voucher_type> 记 </voucher_type> 
			 <fiscal_year>2007</fiscal_year> 
			 <date>2007-01-25</date> 
			 <cashier> 李四 </cashier> 
		 </voucher_head> 
		 <voucher_body> 
			 <entry> 
				 <abstract> 购买保险柜 </abstract> 
				 <natural_debit_currency>15000</natural_debit_currency> 
				 <bill_type> 新增资产 </bill_type> 
				 <auxiliary_accounting> 
					 <item name="dept_id"> 科技信息室 </item> 
					<item name="personnel_id">62101500</item>
				 </auxiliary_accounting> 
			 </entry> 
		 </voucher_body> 
	 <voucher> 
	…
 <vouchers> 


清单 2. 人员信息 XML 片段
                
 <persons> 
	…
	 <person> 
		<code>62101500</code>
		 <name> 张三 </name> 
		 <rsex>2</rsex> 
		 <rpersontype>10</rpersontype> 
		 <bpsnperson>1</bpsnperson> 
		 <cdept_num>12</cdept_num> 
		 <dpvaliddate>2007-8-11</dpvaliddate> 
	 </person> 
	…
 </persons> 
解决之道

分析过应用的需求后发现,我们面临的主要问题是如何对 ERP 提供的 XML 进行处理,包括数据统计和数据之间的关联查询。利用 XPath(XML Path Language)中的 SUM 函数可以实现数据汇总,也可以对 XML 中的节点进行定位和查找。但问题在于,原始的 XML 数据格式(Schema)比较复杂,信息分散在多个 XML 文档中。直接利用原始数据,实现统计、查询这样的操作比较繁琐。另外,我们也需要把一个统一的数据格式提供给前端的展现组件,在进行数据展示时可以更加灵活。在这种情况下,我们设计了一个描述统一台帐信息的 Schema 。


图 20. Schema 逻辑视图
图 20. Schema 逻辑视图

我们可以看到,Schema 中包括了用来统计的指标项,如部门(dept_id)、人员(personnel_id)、日期(date)等。这样我们在做统计时,XPath 表达式会更加简单、清晰。同时也包括之前需要通过跨多个 XML 文档进行关联的项,personnel_id 和 personnel_name 。这样的设计可以简化查询操作,在实现前端展现的时候也更加统一、灵活。

Schema 定义完成后,我们需要考虑把原始的 XML 文档按照 Schema 定义的格式进行转换。在前一章节,我们已经介绍过利用转换构建器可以实现数据复制和合并的方法。但是,转换构建器适用于源模式与目标模式的数据结构差异性不大的情况。一旦原始的 XML 数据结构比较复杂,很难直接设定目标模式与源模式节点间的映射关系。这样,我们需要借助编码,通过程序进行数据的转换。 WPF 提供类型为链接的 Java 对象(Linked Java Object)构建器,使我们可以在模型中调用 Java 代码。

实现步骤和方法

首先将 XML 文档导入 WPF 模型

  1. 在 WPF(已有或新建)项目中,新建一个空的模型。
  2. 将台帐 XML 和人员 XML 文件添加到项目中,如下图:

    图 21. 台帐 XML 和人员 XML 在项目中的路径
    图 21. 台帐 XML 和人员 XML 在项目中的路径

  3. 在模型中添加类型为导入到 XML构建器。在文件路径输入框中提供台帐 XML 文件所处的路径。

    图 22. 引用台帐 XML
    图 22. 引用台帐 XML

  4. 添加类型为简单模式生成器的构建器,生成台帐 XML 的 Schema 。

    图 23. 生成台帐 XML Schema
    图 23. 生成台帐 XML Schema

  5. 导入人员 XML 与台帐类似,不在此赘述。
  6. 在模型中添加类型为 模式 的构建器,定义 统一台帐信息的 Schema

    图 24. Schema 定义
    图 24. Schema 定义

  7. 创建变量,数据类型为统一台帐信息 Schema

    图 25. 用于存储整合后的台帐信息
    图 25. 用于存储整合后的台帐信息

  8. 接下来,实现一个 Java 类,负责把原始 ERP XML 文档中的数据整合到新的 Schema 类型的 XML 变量。 Java 类(TransformVoucherXml.java)创建到 WebContent/WEB-INF/work/source 路径下,如下图:

    图 26. Java 类所在的路径
    图 26. Java 类所在的路径



    清单 3. 把 ERP 提供的 XML 数据整合到新 Schema 类型的 XML 变量
                            
    public void transformXml(WebAppAccess webAppAccess) 
    { 
        // 统一台帐信息 Schema 类型的 XML 变量
        IXml voucherData = webAppAccess.getVariables().
        getXmlElement("voucherData", "vouchers"); 
        // ERP 系统导出的台帐 (Voucher)XML 数据
        IXml voucherXml = webAppAccess.getVariables().
        getXmlElement("voucherXml", "vouchers"); 
        // ERP 系统导出的人员 XML 数据
        IXml employeeXml = webAppAccess.getVariables().
        getXmlElement("employeeXml", "persons"); 
        int voucherSize = voucherXml.getChildren().size(); 
        List oldVoucherList = voucherXml.getChildren(); 
        IXml tVoucherNode = null; 
        IXml tOldVoucherNode = null; 
        String personnelId = ""; 
        String personnelName = ""; 
        // 把 ERP 提供的 XML 数据复制到新 Schema 类型的 XML 变量
        for (int i = 0; i < voucherSize; i++) 
        { 
            tOldVoucherNode = (IXml) oldVoucherList.get(i); 
            // 添加 voucher 元素
            tVoucherNode = voucherData.addChildElement("voucher"); 
            // 添加 company 元素
            tVoucherNode.addChildWithText("company", 
    	tOldVoucherNode.findElement("voucher/voucher_head/company").getText()); 
            // 添加 dep_id 元素
            tVoucherNode.addChildWithText("dept_id", tOldVoucherNode.findElement(
    	    "voucher/voucher_body/entry/auxiliary_accounting/item[@name=dept_id]/")
    	    .getText()); 
            // 添加 fiscal_year 元素
            tVoucherNode.addChildWithText("fiscal_year", 
    	tOldVoucherNode.findElement("voucher/voucher_head/fiscal_year").getText()); 
            // 添加 date 元素
            tVoucherNode.addChildWithText("date", 
    	tOldVoucherNode.findElement("voucher/voucher_head/date").getText()); 
            // 添加 abstract 元素
            tVoucherNode.addChildWithText("abstract", 
    	tOldVoucherNode.findElement("voucher/voucher_body/entry/abstract").getText()); 
            // 添加 natural_debit_currency 元素
            tVoucherNode.addChildWithText("natural_debit_currency", 
    	tOldVoucherNode.findElement("voucher/voucher_body/entry/natural_debit_currency")
    	    .getText()); 
            // 添加 bill_type 元素
            tVoucherNode.addChildWithText("bill_type", 
    	tOldVoucherNode.findElement("voucher/voucher_body/entry/bill_type").getText()); 
            // 添加 personnel_id 元素
            personnelId = tOldVoucherNode.findElement(
    	"voucher/voucher_body/entry/auxiliary_accounting/item[@name=personnel_id]")
    	    .getText(); 
            tVoucherNode.addChildWithText("personnel_id", personnelId); 
            // 通过 personnel_id 在人员 XML 中查找 personnel_name 
            personnelName = employeeXml.findElement(
    	"v_aa_hr_hi_person/[code=" + personnelId + "]/../name").getText(); 
            // 添加 personnel_name 元素
           tVoucherNode.addChildWithText("personnel_name", personnelName); 
        } 
    } 
    

    通过清单 3 中的代码,数据已经按照新 Schema 定义的数据结构整合到一个 XML 变量中。接下来,我们会依据一些指标对数据进行统计,如:部门、日期和人员等。 IXml 接口并没有提供相应的方法完成此类功能。我们需要借助一些时下流行的 XML 处理器,如:Xalan(http://xalan.apache.org)或 XMLBeans(http://xmlbeans.apache.org)去处理。在此,不做过多介绍,请参考相应的资源。

  9. 在模型中添加类型为 链接的 Java 对象 构建器。

    图 27. 把 Java 类引入模型
    图 27. 把 Java 类引入模型



    图 28. 在模型中可以调用 Java 类的公用方法
    图 28. 在模型中可以调用 Java 类的公用方法

  10. 最后,我们便可以利用像视图和表单Web 图表等展现端构建器显示统计结果。

    图 29. 显示统计结果
    图 29. 显示统计结果





回页首


结束语

使用 WPF 开发的应用,XML 作为统一的数据格式,真正做到了数据格式的系统无关性。借助这一特性,使之成为一款名副其实的符合 SOA 规范的开发工具。在多数情况下,直接利用构建器的功能处理 XML 便可以满足应用的要求,而无需进行任何编码。同时,我们也可以利用系统提供的 API 去应对一些特殊情况。






回页首


下载

描述名字大小下载方法
本文样例代码。HandleXMLDemo.zip8 KBHTTP
关于下载方法的信息


参考资料

学习

讨论


关于作者

高爽,IBM(中国)软件部工程师,负责合作伙伴技术支持。领域涉及 WebSphere Portal 及相关解决方案,具备丰富的门户应用开发经验。




对本文的评价








IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款