级别: 中级 Hardeep Singh, 高级技术开发, Systems Documentation, Inc. (SDI)
2008 年 9 月 10 日 本文是关于 IBM® Mashup
Center 中的 InfoSphere™ MashupHub 的系列中的第 2 篇文章。该系列包含两部分,第 1 部分 讨论了产品架构和它的工具及实用程序,并介绍了一个简单的用例场景。现在,在第 2 部分中,您将更加深入地探索该工具,并扩展用例场景,展示不同的组件,以及阐释使用 Web 2.0 概念(例如企业中的数据 feed 和 feed mashup)的优点。
简介
XML feed 格式的各种业务信息流本身就充满了乐趣。然而,只有当您开始混合多个 feed 来解决一个业务问题时,Web 2.0 mashup 的真正威力才会显现出来。之前由于缺乏公共数据基础设施而对于企业遥不可及的信息集成解决方案,现在似乎突然可以实现了。现在,无需专用的应用程序,也无需大宗买进巨大的层次结构产品,个人就可以利用跨公司的信息来解决业务问题。
feed mashup
要支持这种 feed 合并,需要一个基础设施,以便在其中缓存、过滤、连接、存储和转换来自不同 feed 的数据。IBM Mashup Center 的 Feed Mashup Editor 和 Feed Mashup Engine 就提供了这样的基础设施。
图 1. Feed Mashup 的架构
由于没有标准化的语言用于创建 mashup,所以需要由引擎定义用于实现 mashup 应用程序的格式。IBM Mashup Center 的 Feed Mashup Engine 定义了很多可对 mashup 中的 feed 数据执行的操作。这些操作通过一个基于 XML 的模型向 mashup 开发人员公开。
Mashup Editor Client
Mashup Editor Client 通过将操作图形化地向开发人员公开,为创建 mashup 应用程序提供集成开发环境(IDE)。本文主要关注 Mashup Editor Client,通过一个易于理解的用例场景展示操作符的用法和功能。
模型
客户机 mashup 使用 XML 格式,并且在一个内存中的 DOM 模型中进行维护和修改。对 mashup 的任何更改都会自动反映到模型中,然后 GUI 被更新,以反映更改。
在任何时候,都可以通过单击画布,然后按下 CTRL+M 来查看 mashup 模型。这将弹出 Mashup Model View 对话框,其中显示客户机 XML 模型,这个模型可以是层次结构,也可以被串行化为字符串格式。
mashup 流信息位于 /mashup/flow 分支中,而 feed 数据则存储在 /mashup/data 分支中。
注意:为了增加可读性,本文所有对路径的引用都省略了名称空间。
图 2. Mashup Editor Client XML 模型
预览
当单击 Preview 选项卡时,模型被串行化并发送到 IBM
Mashup Center 的 MashupHub 服务器。在这里,客户机 XML 模型在被 feed mashup 引擎处理之前被转换成引擎 XML 模型。
清单 1. 预览 XML
<MASHUP>
<METADATA>
<FLOW-SCHEMA-VERSION>development</FLOW-SCHEMA-VERSION>
</METADATA>
<NAMESPACES>
<NS prefix="flow" uri="http://ibm.com/mashuphub"/>
<NS prefix="mhub" uri="http://w3.ibm.com/mhub"/>
<NS prefix="atom" uri="http://www.w3.org/2005/Atom"/>
</NAMESPACES>
<IMPORT-FEED ALIAS="$source6347">
<ITEM OUTVAR="$source6347 " FTYPE="ATOM" TYPE="URL" FRESHNESS="3600">
<SOURCE>
<![CDATA[http://localhost:8080/mashuphub/client/plugin/generate/entryid/16/pluginid/3]]>
</SOURCE>
<CONTAINER><![CDATA[/atom:feed/atom:entry]]></CONTAINER>
</ITEM>
</IMPORT-FEED>
<INPUT/>
</MASHUP>
|
预览的操作符所产生的 XML 输出被返回到客户机,并存储在其中的客户机模型中。
加载源 feed 的过程
当加载一个源 URL 时,要对服务器执行两个调用。第一个调用返回源的实际数据表示,后者被存储在 /mashup/data/sourcexml 中。
编辑器尝试分析该数据,以确定 feed 类型(例如
RSS/ATOM/XML)。然后,它在模型中设置 feed 类型,同时执行对服务器的第二次调用。引擎返回 feed 结果的 ATOM 表示,后者被存储在客户机模型中的
/mashup/data/feed 中。
图 3. 客户机模型源数据缓存
注意:所有其他操作符都执行一个调用并输出结果,结果的格式为 ATOM,存储在 /mashup/data/feed 路径中。在一个预览调用中,最多返回 50 个条目。但是对于 source 操作符的第一个加载调用所返回的数据,没有最大限制。
高级选项卡
编辑器猜测 feed 类型之后,自动为定义源中的业务数据的重复元素设置路径。也可以手动地识别重复的数据元素,以便仅将该元素添加到预览结果的每个条目中。
例如,在销售情报 feed 结果中,只有 row 元素和它的后代中的数据是 mashup 所需的。
图 4. 包含默认重复元素的 feed 结果
如果查看客户机模型中的源元素,您将会注意到,为第二个调用自动设置的重复元素的路径是 /feed/entry。
图 5. 包含默认重复元素的客户机模型
为了只提取 feed 条目中的 row 元素,需要将重复元素路径改为
/feed/entry/content/row。这可以在 Advanced 选项卡中使用表示原始 feed 数据的下拉树(/mashup/data/sourcexml)来完成。
当从 Feed Type 下拉框中选择 XML feed 类型时,Repeating Element
下拉树被启用,可以从树中选择元素路径。还可以手动修改这个路径,只是要小心名称空间前缀。
图 6. 在 Advanced 选项卡上设置新的重复元素
底层模型被更新,以反映源中重复元素的新路径。
图 7. 客户机模型反映 Advanced 选项卡上对重复元素路径的更改
再次预览源数据时,为 feed mashup 引擎生成的 XML 现在反映新的重复元素和 feed 类型。
清单 2. 包含重复元素和 feed 类型的 XML 预览
<MASHUP>
<METADATA>
<FLOW-SCHEMA-VERSION>development</FLOW-SCHEMA-VERSION>
</METADATA>
<NAMESPACES>
<NS prefix="flow" uri="http://ibm.com/mashuphub"/>
<NS prefix="mhub" uri="http://w3.ibm.com/mhub"/>
<NS prefix="atom" uri="http://www.w3.org/2005/Atom"/>
<NS prefix="ns3" uri="http://www.ibm.com/xmlns/atom/content/datarow/1.0"/>
</NAMESPACES>
<IMPORT-FEED ALIAS="$source6347">
<ITEM OUTVAR="$source6347" FTYPE="XML" TYPE="URL" FRESHNESS="3600">
<SOURCE>
<![CDATA[http://localhost:8080/mashuphub/client/plugin/generate/entryid/16/pluginid/3]]>
</SOURCE>
<CONTAINER>
<![CDATA[/atom:feed/atom:entry/atom:content/ns3:row]]>
</CONTAINER>
</ITEM>
</IMPORT-FEED>
<INPUT/>
</MASHUP>
|
对引擎的新的预览调用的结果使结果集中的每个条目只包含 row 元素和它的后代。这种方法的主要优点是,当这个源 feed 条目被用于其他操作符中时,可以减少不相关的数据层次结构对它的干扰。
图 8. source 操作符输出,重复元素被设为 row
场景
第 1 部分 中使用的场景创建了一个 mashup,以更好地根据销售情报预测库存需求,这个场景被刻意保持为只有一个基本框架。该场景只考虑一条销售情报,产生的 mashup feed 计算销售给一个客户的每项产品的库存需求。
图 9. 第 1 部分中简单的用例 mashup
本文的场景扩展了前一个场景,使 mashup feed 对于产品管理更加有用,在此过程中还加入大部分操作符。它考虑来自所有销售人员的销售情报,并计算所有客户对于一项给定产品的综合库存需求。
将所有销售情报组合到一个输出中
原始场景要求所有销售人员根据他们的销售情报电子表格创建 feed,并允许产品经理访问相关信息。在 第 1 部分 中,为了简化问题,只考虑一个销售 feed,而本文中增强的场景则考虑所有可用的销售情报。
通过拖入一个 source 操作符,然后从目录中加载相关的销售情报 feed,将每项销售情报添加到画布上。
下一步是将不同的销售情报源组合成一个单独的输出。
注意:这个步骤相当于在一个 SQL 查询中执行一个 UNION。
从面板中拖入
combine
操作符,并将每个销售情报源的输出插到 combine 操作符的插槽中。
图 10. 用于将所有销售 feed 添加到一个输出中的 combine 操作符
combine 操作符需要两个或更多输入,merge 和 foreach 操作符需要两个输入,所有其他操作符只接受一个输入,而 source 操作符不接受任何输入。用于 combine 操作符的 4 个连接的输入被反映在客户机模型中。
图 11. 客户机模型显示 combine 操作符的多个输入
来自每个源的条目被无条件地附加到 combine 操作的输出中,结果包含所有输入源中的全部条目。
图 12. combine 操作符的输出包含所有条目
将条目按产品 ID 分组
从前一个图中可以看到,对于每项产品,combine 操作的输出可以有多个条目。为了计算所有暂定客户对某项产品的库存需求,需要将一个给定产品的所有销售条目组合到一个条目中。
将一个 group 操作符拖放到画布中,然后将 combine 操作符的输出连接到 group 操作符的插槽中。
接下来的步骤是识别用于将销售条目分组的键路径。这可以通过单击 Group element
下拉框,然后选择到 row/col_C/text() 节点的路径(指向条目的产品 ID 值)来完成。
从 Associated Data Element 下拉框中选择
row 元素,以表明该元素将被添加到组中。
图 13. 将条目按 ID 分组
对 group 操作符的修改被应用到底层客户机模型中。注意,group 操作符网格中的每一行在模型中被表示为一个 param 元素,而路径信息则被存储在该元素的文本节点中。param 元素用于存储模型中的任何 text/variable/path 数据,而数据的类型是由 type 属性定义的。这里将覆盖 operatorspecific 属性,并根据包含的操作符类型来解释它。
图 14. 客户机模型显示 group 操作符的参数值
要查看 group 操作的结果,可以进入 Preview 选项卡。一个给定产品 ID 的所有行都被组织在一起,并位于 nestval 元素下。
图 15. 按产品 ID 分组的结果
转换输出以聚合每笔销售的数量
只有每项产品的订购总单位数是计算库存需求时所需要的,所以可以使用一个 transform 操作符去掉一些不必要的信息。
将一个 transform 操作符拖放到画布中,然后将
group 操作符的输出连接到它上面。
左边的
Input 树显示来自 group 操作符的输出的一个条目,而右边的 Output 树则定义转换的输出模板。可以通过从 Input 树中拖放元素或属性,或者使用该树的上下文菜单,将新的元素或属性添加到 Output 树中。
在 Input 树中创建一个新的名为
product 的元素,并为它添加一个属性 pid。现在将
entry/groupval 文本节点拖放到这个属性上。
注意:如果拖放时遇到问题,那么也可以使用 Input 树的上下文菜单。首先选中 Output 树中的目标节点,然后在 Input 树的源节点上单击右键,并选择
Copy to the output tree。
图 16. 使用 transform 操作符创建包含产品 ID 和分组 feed 的 total_units 的新的输出格式
函数
为了合计出每项产品需要生产的总单位数,将一个求和函数添加到 output 树。
首先,在 product 元素下创建一个新元素 total_units,然后通过在上下文菜单中选择 Specify a function value 将一个函数添加到这个元素。
在函数的对话框中,从函数的下拉列表中选择聚合函数
Sum。一个列出用于该函数的所有参数的适当网格将出现在函数选择框下。
在函数的 expression 参数的 Value 单元格中,可以输入一个文本字符串,指定用于在运行时获取值的 Input 中的路径,然后从一个嵌入式函数获得结果,或者也可以在运行时从一个变量中获取值。
由于需要将所有数量加到一个条目中,所以必须指定数量值在 input 中的路径。为此,选择 Value 下拉框中的
Specify values from the Input tree 选项。在 Input 树对话框中,选择数量节点的路径(用于 col_E 的文本节点)。
图 17. 将一个聚合函数添加到 transform 输出中,以计算一个产品所有单位的总数
当尝试预览转换的结果时,会收到一个服务器异常,表明在指定路径中发现一个非数字型数据单位。
图 18. 输入 feed 中存在非数字型数据而导致的服务器错误
在预览 combine 操作符的输出时可以看到,在从一个 Excel 电子表格创建销售情报 feed(请参阅 第
1 部分 中的 “来自电子表格的 feed” 小节)时指定的标题行造成了不必要的数据。
图 19. 存在非法数据的原因是每个销售 feed 中的标题信息
过滤掉错误的数据
为了计算每项产品被订购的总单位数,首先需要从 combine 操作符的输出中去掉那个路径中所有非数字的条目。这就需要在将 combine 的输出传递给 group 操作符之前对它进行过滤。
将一个 filter 操作符拖放到画布中。将 combine 操作符的输出与 group 操作符的连接断开,然后将 combine 操作符的输出连接到 filter 操作符。将 filter 操作符的输出连接到 group 操作符的输入。
在 filter 操作符中,添加一个用于选择条目的条件,以便不 包含数量节点(col_E)的值中的单词 “units”。
图 20. 过滤组合的销售 feed,以去掉单位节点中包含非数字字符的条目
从客户机模型中查看这个操作符,您将会注意到,一个 condition 元素被添加到该操作符中,并且 condition 元素的 operation 属性被设置为
notcontains。而且,第一个参数的文本值包含数量节点的 xpath 位置,而第二个参数的文本值则包含字符串
“units”。
图 21. 客户机模型反映了去除非数字数据的过滤条件
重要:断开与 group 操作符的输入的连接的一个结果是,在 group 操作符中设置的所有条件和参数都变得无效,需要重新创建它们。
当 group 操作符以后的所有动作重新执行之后,如果单击 transform 操作符的 preview 选项卡,则对于每项产品,结果中将包含一个单独的条目,其中包含产品 ID 和被订购的单位总数。
图 22. 非数字数据被去除后,组合的销售 feed 可以被正确地转换
使用产品 ID 获得产品细节
接下来的步骤是获得销售列表中每项产品的详细信息。为此,首先需要从目标中加载产品源,然后为它添加一个过滤器。这一步在 第 1 部分 中已经提及(请参阅那篇文章的 “创建产品 feed 上的过滤器”)。
获得销售列表中每项产品的细节
对于组合的销售列表中每个被转换的条目,使用产品 ID 作为键获取关于产品的详细信息。
这一步可以通过对组合的销售列表(主列表)中的每个条目进行循环,并从过滤后的产品 feed 中获取每项产品的详细信息来完成。组合的销售列表中的产品 ID(/entry/product/pid)被传递到 get one product 过滤器的 pid 变量,以选择那个产品的详细信息。
图 23. 使用 foreach 操作符获取转换后的销售列表中每个条目的产品详细信息
这个操作的结果是,为销售列表中的每项惟一的产品生成一个条目,其中包含该产品被订购的总单位数和关于该产品的详细信息。
图 24. foreach 操作的结果将产品详细信息添加到每个转换后的销售条目中
转换列表以获得每项产品所需的资金
为了确定每项被订购的产品所需的资金,需要计算那项产品被订购的所有单位数的总重量。
再次使用 transform 操作符过滤掉不相关的数据,并计算每项产品的总重量。
由于需要将总单位数乘以每个单位的重量,所以从函数列表中选择
Numeric Multiply 函数。对于第一个参数,选择到
total_units 节点的路径;对于第二个参数,选择到
weight
节点的路径。
图 25. 使用 transform 操作符计算每项产品被订购的所有单位数的总重量
转换的结果现在包含一项给定产品被订购的所有单位数的总重量。该信息现在可用于计算原材料需求。
图 26. 转换的结果显示每项产品被订购的所有单位数的总重量
将输出按产品 ID 升序排序
可以将转换结果排序,使最终的 feed 结果按产品 ID 升序列出条目。
拖放一个 sort 操作符,将 transform 操作符的输出连接到它的输入。
从下拉树中选择
pid 属性。这提供了用于对条目排序的值的路径。
图 27. 将结果按产品 ID 排序
在 Publish 操作符中设置与 feed 类型相关的信息
最后,将 sort 操作符的输出连接到 publish(端点)操作符。
选择 RSS 作为 feed 类型,并输入 RSS feed 所需的标题信息。
图 28. 设置 mashup feed 类型
单击 Run,在浏览器中显示 mashup feed 输出。
图 29. 调用 mashup URL 的 feed 结果
修改 mashup,尝试下面的操作
- 计算每项产品在指定日期的库存需求
- 计算所有产品的总重量
- 计算打包类型和所需数量(提示:使用 size)
使用变量动态绑定运行时参数
在很多情况下,需要在运行时动态地传递一个参数值。例如,在 “get one product filter” 条件中就使用了一个变量来返回在运行时其 ID 被传递给操作符的产品的详细信息。
如果它是一个 SQL 查询,那么它相当于下面这个参数化的查询:
Select * from product where pid=?
|
如果它是一个程序,那么它相当于一个函数,变量值在该函数的一个参数中传递:
Object get_one_product(String pid)
{
Hashtable product_list = call_get_product_list_hashtable_function();
return list.get(pid);
}
|
在运行时,有两种方法初始化 mashup 中定义的变量:
- 用外部(主)feed 中的数据初始化 foreach 操作的内部 feed(详细信息)的变量。在这个场景中,当将产品详细信息添加到销售列表中的每项产品条目中时,就要进行这样的初始化。下面的伪代码解释 foreach 操作中变量绑定的过程。
for(i=0; masterlist.length >i ;i++)
{
String pid = masterlist[i].getpid ();
Object productdetails =get_one_product(pid);
masterlist[i].adddetails(productdetails)
}
|
- 将值作为参数传递给 mashup URL。例如,如果将 mashup 的内部部分(产品详细信息)创建为一个单独的 feed,那么该产品详细信息 mashup 的 URL 将 pid 变量公开为它的参数。
图 30. 创建一个单独的 mashup,以获得一个给定产品 ID 的产品详细信息
该 mashup 的 feed URL 将 pid 变量公开为一个参数,它的值被设为在创建该变量时定义的默认值。
http://localhost:8080/mashuphub/client/plugin/generate/entryid/79/pluginid/10?pid=100-101-10
图 31. pid 变量被作为参数添加到 URL 中
如果单击 View Feed 链接,变量中定义的描述字符串被用于提示修改 URL 参数中的 pid 值。
注意:默认值已经在参数字段中被设置。
图 32. 查看 feed 时,用户被提示设置变量值
变量的作用域
变量的创建是在将它们赋给一个参数或条件(通过在 condition/parameter grid Value 下拉框中选择 Use a variable to return the value 选项)的同时创建的。
默认情况下,创建的变量被自动选定并分配给条件,但是也可能一次创建多个变量,并将其中 0 个或任意个变量赋给操作符/函数的那个参数/条件值。
这意味着即使一个变量是在一个操作符中创建的,其作用域仍然取决于它在哪里被赋值。这一点也决定了是在外部(在 mashup URL 中参数化)公开它还是在内部设置它。
是否将变量参数化到 mashup URL 中取决于是否在一个 foreach 循环中为它赋值:
- 如果与 foreach 操作符的详细信息输入相关联的一个变量是使用来自主输入的数据初始化的,那么该变量不会作为参数添加到 mashup URL 中。
- 如果一个变量没有与 mashup 中的任何参数或条件相关联,那么它被忽略。
- 所有与 mashup 中任何操作符中的某个参数或条件相关联的其他变量,都被参数化到 mashup URL 中。这使得 mashup 的使用者可以通过更改 mashup URL 中的参数值动态地修改它的结果。
mashup 中创建的所有变量都被作为参数添加到模型中的
/mashup/flow/variables 路径中。
图 33. 所有变量都被存储在客户机模型中的 /mashup/flow/variables 元素下
转换数据类型
当没有模式时,XML 数据值被当作字符串对待。这并不会影响本场景中的排序结果,因为产品 ID(pid)是字符串类型。然而,在很多其他情况下(例如按日期排序),则必须将选定路径上的值转换为一个特定的数据类型。这可以通过使用下拉树的上下文菜单来完成。
右键单击要选择的节点,从菜单中选择数据类型。
注意:这一步不会关闭下拉树,因为设置一个数据类型并不表示完成了节点的选择。
数据类型转换只适用于设置操作符的位置,当生成引擎 mashup XML 时,类型信息被用于将指定路径中的值转换为指定的数据类型。
注意:虽然数据类型转换主要用于排序,但是也可以在其他操作符中使用。
图 34. 数据类型转换
结束语
在 Web 2.0 中,如果将 Intranet 比作一个松散耦合的 XML feed 数据源的数据库,那么 feed mashup 引擎就相当于数据库引擎,而 feed mashup 编辑器则相当于一个 SQL 查询构建器。现在,显然可以实现跨越组织和部门边界的简单的信息共享和集成目标了。
参考资料 学习
获得产品和技术
-
IBM Mashup Center:找到一个易于使用的业务 mashup 解决方案,这种解决方案支持动态情景应用程序的业务线装配,并具有 IT 部门所需的管理、安全性和治理功能。
-
使用可直接从 developerWorks 下载的
IBM
试用软件 构建您的下一个开发项目。
讨论
关于作者  | 
|  | Hardeep Singh 是高级技术小组的成员。他是 InfoSphere MashupHub Mashup Editor 的架构师。他拥有超过 24 年的行业经验。 |
对本文的评价
|