创建并置表,第 1 部分:使用 Flex 创建 JTable 介绍了使用并置表(JTable)这一二维可视化辅助工具来排列、分类和比较大量数据。JTable 是 IBM Research 正在进行的 Business Insight Toolkit (BitKit) 原型应用程序开发的一部分。该团队已经实现了一个 JTable,称作 IBM Rational System Architect (SA) 产品套装的矩阵查看器,并作为 SA/XT (eXtended Team) web 应用程序的一部分。
本文用两个例子演示矩阵查看器的实现:
- 基本矩阵样例演示了如何创建一个简单的二维矩阵查看器,它的源数据嵌在代码中。
- 矩阵查看器样例演示了实现 XML 数据源的查看器的实现。
两个例子都使用了 Dojo Toolkit(见 参考资料)。为了使样例运行,可以从 下方下载表 中下载各自(developerWorksBasicMatrix 和 developerWorksMatrixViewer)的源代码。
本文假定您熟悉 Dojo JavaScript Toolkit 和 HTML 编程。
本文场景中有个虚构的 AllSportTicks 公司,它出售专业体育赛事的门票,包括 MLB、NFL、NHL 和 NBA。AllSportTicks 想要将市场扩展到美国东北区,需要分析哪些体育赛事门票需求最大。该公司使用了一个软件程序以二维矩阵方式查看数据。想象一下,简单起见,分析数据的标题是 “该城市有联赛球队吗?”。水平维度是男子职业体育机构列表。竖直维度是东北地区的城市列表。单元格是这些城市的联赛球队。
当运行 Basic Matrix 样例(下方下载表 中的 developerWorksBasicMatrix)时,您会看到一个二维矩阵,它的列和行的标题看上去相同,使用也相同。但与矩阵主体不一样,如图 1 所示。
图 1. developerWorksBasicMatrix 的浏览器中有一个矩阵
用 Dojo 的 dojox.grid.DataGrid 组件实现基本矩阵。本文中,将用到两个术语:标题单元格与内容单元格。我们将标题单元格 定义为顶部或侧边的标题,也称为水平和竖直维度。我们将内容单元格 定义为网格主体中非维度的单元格。再看一眼图 1,您会发现我们将网格最左边的列转换成竖直维度,标题为城市:Buffalo、Philadelphia 和 Pittsburgh。
要实现这个基本矩阵小部件,首先需要创建网格的结构。清单 1 中的 layout 变量用于设置结构。
清单 1. 设置矩阵结构
var rowHeaderColumn = {
noscroll: true,
cells: [{ name: 'City', field: 'city', width: 6,
styles: 'border-width: 1px; background: #D9E8F9; '}]};
var columnHeaders = {cells:[]};
var layout = [rowHeaderColumn,columnHeaders];
|
还有,rowHeaderColumn 和 columnHeaders 数组定义了 layout。rowHeaderColumn 用来锁定最左侧列的宽度,并用淡蓝色填充。这两项设置让我们能将网格第一列转换成矩阵的竖直维度。要锁定最左侧列,要将 rowHeaderColumn 的 noscroll 属性设置为 true。要填充淡蓝色,需要将风格属性的 background 属性设置为 #D9E8F9。
水平维度的可滚动列是由 JSON 数组 cells 定义的。水平维度的标题单元格 MLB、NFL、NBA 和 NHL,风格一致,都是淡蓝色。可以通过重新定义 dojo/dojox/grid/resources/Grid.css 改变标题单元格背景,如下所示。
清单 2. 定义列标题
columnHeaders.cells.push({field:"MLB",name:"MLB"});
columnHeaders.cells.push({field:"NFL",name:"NFL"});
columnHeaders.cells.push({field:"NBA",name:"NBA"});
columnHeaders.cells.push({field:"NHL",name:"NHL"});
.dojoxGridHeader .dojoxGridCell
{
background: #D9E8F9;
}
|
和 Dojo 中很多小部件一样,网格有其自己的数据模型,称为数据存储,可让网格访问。我们使用 Dojo 类 dojo.data.ItemFileReadStore 来初始化 dataStore。该函数从 JavaScript 对象 rowData 中读取 JSON 结构化内容,如清单 3 所示。
清单 3. 创建并设置数据存储
var rowData = {items:[]};
rowData.items.push({"city":"Buffalo","MLB":" ","NFL":"Bills",
"NBA":" ","NHL":"Sabres"});
rowData.items.push({"city":"Philadelphia","MLB":"Phillies",
"NFL":"Eagles","NBA":"76ers","NHL":"Flyers"});
rowData.items.push({city:"Pittsburgh","MLB":"Pirates","NFL":"Steelers",
"NBA":" ","NHL":"Penguins"});
var dataStore = new dojo.data.ItemFileReadStore({data:rowData});
|
键/值对(city:< value >)是竖直维度的头部标题。填入竖直维度的标题数据是将网格最左侧列转换成矩阵竖直维度的第二步,也是最后一步。
当我们初始化这个网格小部件(dojox.grid.DataGrid)时,数据存储和结构共同定义了网格。下一项任务是将网格(domNode)的内部属性添加到页面的容器节点中。网格可显示前的最后一步是通过调用 startup 来呈现网格。呈现网格会引起子部件创建并加入页面,如清单 4 所示。
清单 4. 定义、呈现及向页面添加网格
grid = new dojox.grid.DataGrid({
id: "grid",
store: dataSore,
structure: layout
}, document.createElement('div'));
dojo.byId("gridContainer").appendChild(grid.domNode);
grid.startup();
|
基本矩阵样例与 矩阵查看器 样例主要的不同是矩阵查看器从 XML 文件获取数据,而基本样例使用的是嵌在代码中的数据。
在演示如何实现矩阵查看器之前,让我们先在下一节中看看数据源 XML 是如何生成的。
Dojo 网格的数据源可以是数据库、REST 服务或者是 JSON 文件。我们的例子使用了 XML 数据格式,它定义了矩阵查看器显示的所有矩阵的模型内容。这个 XML 定义了行、列和单元格内容。单元格的内容是由 XML 中行和列数据相交生成的。XML 遵循矩阵查看器模式(XSD)的数据格式。
该模式使用 XML 模式语言生成,并遵循 IBM Rational 的模式设计指导。指导原则之一是将大量资源数据存储在元素中。只对惟一数据标识使用属性。下面的图 2 右侧显示了一个样例。(您可以查看本文 下载 中的模式。)
图 2. 矩阵查看器架构
将构造矩阵模型内容的责任交给 XML 提供程序。在 developerWorksMatrixViewer 样例中,已生成四个 XML 文件。在利用此技术的实际工具中,XML 文件一般是由计算行和列维度的服务器逻辑生成,然后将相应数据交叉生成单元格内容。因此我们选择 XML 作为数据格式 — 从而这些工具可以将生成的 XML 文档与矩阵查看器所需的对应的 XML 模式进行验证。
矩阵查看器的责任是解析 XML 文档,以 Dojo DataGrid 所需的格式组织矩阵的数据,然后在 web 页面上显示矩阵。
如您在 构建基本矩阵 一节中所见,我们想要构建一个水平和竖直标题与主体都不同的网格。我们想要每个单元格包含的数据都是由对应标题交叉生成。
为了演示矩阵查看器的实现,我们将修改并扩展此场景,将有更多的城市,有四个不同的矩阵以显示多个数据。其维度与基本矩阵一致。水平维度是男子职业体育机构;竖直维度列出东北地区的城市。
运行此例后,您将看到有四个标签的表形视图,如图 3 所示。单独运行各个不同部分会在单元格中显示不同类型的数据。
图 3. 运行 developerWorksMatrixViewer 后在浏览器中显示矩阵浏览器
标签的功能概括如下。
| 选中此标签... | 显示... |
|---|---|
| City has Pro Team? | 单元格中显示 X,它表示该城市中至少有一支联赛球队
|
| Team Names by City | 该城市中所有球队 出现一个二维目录项(见图 3)。每个标题单元格只有一项,背景有颜色。每个内容单元格包含不止一项,背景为白色。矩阵有下划线,表示有标题和内容单元格的链接。 |
| Champions since 2000 | 单元格中某些球队背景为黄色表示球队自 2000 年以来曾赢得冠军(一个可能会吸引更多人买票的原因)。 |
| Market Potential | 根据最近的表现显示市场潜力(差、中、优),用三种圆圈表示:红、黄、绿。 |
简单起见,矩阵查看器样例中是齐次矩阵(homogeneous matrices),即每个矩阵维度只包含一个部分。以下的清单 5 显示了 XML 中用于 图 3 矩阵的三段摘录。第一段是水平维度,第二段是竖直维度,第三段是内容单元格。developerWorksMatrixViewer 样例中用到的四个 XML 都能从 下方下载表 中下载得到。
清单 5 中对应 New York City 和 MLB 的单元格包含不止一支球队。SA/XT 矩阵查看器的要求之一是允许在一个内容单元格中能显示不止一个元素。为了实现这个功能,我们将 XML 模式设计为在单元格中支持元素列表,而不仅时候支持字符串和多信息文本(rich text)。
清单 5. 图 3 显示的 XML 片段
<columnDimension>
<label>Professional Sport Organizations</label>
<sections>
<section>
<header id="01" href=
"http://en.wikipedia.org/wiki/Major_League_Baseball" >
<label>MLB</label>
</header>
. . .
</section>
</sections>
</columnDimension>
<rowDimension>
<label>Cities</label>
<sections>
<section>
<header id="10" href="http://en.wikipedia.org/wiki/New_York_City" >
<label>New York City</label>
</header>
. . .
</section>
</sections>
</rowDimension>
<cell id="11">
<cellDefinitionRef href="#cellDef" />
<location>
<columnRef href="#01" >
<rowRef href="#10" >
</location>
<contents>
<listItems>
<listItem href=
"http://en.wikipedia.org/wiki/New_York_Mets"/>
<contents>New York Mets</contents>
</listItem>
<listItem href=
"http://en.wikipedia.org/wiki/New_York_Yankees">
<contents>New York Yankees</contents>
</listItem>
</listItems>
</contents>
</cell>
|
实现部分的开始是将 清单 1 中的基本矩阵样例代码转换成 developerWorksMatrixViewer.js 文件中的矩阵查看器样例。这是定义矩阵。这里我们是做一对一的转换。然后,当我们引用清单时,它们就来自这个文件。
XML 解析后,矩阵水平维度的标题 columnHeaders 就用 field:headerId 和 name:headerLabel 键/值对填充。解析和填充都在 processColumnSection 函数内部完成,它是由 processColumnDimension 函数调用的。清单 6 显示了此样例。
清单 6. 解析和填充列标题
function processColumnSection(section)
{
for (var i = 0; i < getXMLChildLength(section); i++)
{
var sectionChild = getXMLChild(section,i);
if(sectionChild.tagName = "header")
{
headerId = sectionChild.getAttribute("id");
href = sectionChild.getAttribute("href");
var labelNode = getXMLChild(sectionChild,hc);
if (labelNode.tagName == "label")
{
headerText = labelNode.text;
. . .
}
. . .
headerLabel =
formatColumnHeader(headerText,href);
}
. . .
columnHeaders.cells.push=(
{field:headerId, name:headerLabel,
width:‘auto’, header: headerText});
}
}
|
headerText 和 href 由 formatColumnHeader 标记,是为了创建标题链接。(header:headerText 键/值对将在以后用来创建单个单元格的提示。)
竖直维度的标题构成了 rowData 存储最左边的列。此列用 field:headerId 和 name:headerLabel 键/值对填充,而 XML 由 processRowDimension 函数调用的 processRowSection 解析。这两个函数与创建列维度的函数一样;惟一不同是行维度的数据是 rowData 存储的一部分:
rowData.items.push({field: headerId, name: headerLabel, header:headerText}); |
清单 7 显示如何继续构造 rowData 存储。在 XML 中,每个矩阵单元格位置通过引用两个标题定义:水平的和竖直的。在 processCell 函数中,首先将 XML 文件解析为:
- 获取矩阵中单元格的位置(x, y)
- 获取单元格的值
- 指定数据存储元素的值
调用 formatCellLink 和 applyStyle 函数来改变单元格中数据的显示方式。
清单 7. 解析、填充和呈现单元格数据
function processCell(cell, columns)
{
. . .
if (x && y && value)
{
for (var j = 0; j < rowData.items.length; j="" )
{
if (rowData.items[j].field == y)
{
. . .
value = formatCellLink(value, href, image);
. . .
value = applyStyle(value,
getStyleProperties(styleMap));
rowData.items[j][x] = value;
. . .
}
}
}
}
|
此例中,loadGrid 函数中同时处理存储和结构,而该函数是由 loadWidget 函数调用的。见清单 8。dataStore 中是空值,默认情况下单元格中显示 “undefined”,它将作为空字符串(无数据的单元格)重新呈现。这通过重写网格的 get 函数完成。
清单 8. 加载网格
function loadGrid()
{
var dataStore = new dojo.data.ItemFileReadStore({data: rowData})
grid = new dojox.grid.DataGrid(
{
page: pageTitle,
title: tabTitle,
description: tabDescription,
id: tabTitle,
store: dataStore,
structure: layout,
escapeHTMLInData: false,
get: function(rowIndex, inItem)
{
var grid = this.grid;
var dereference = function(item, field)
{
var props = field.concat().split('.');
var value = item;
dojo.forEach(props, function(prop)
{
value = grid.store.getValue(value, prop);
if ( !dojo.isString(value))
value = " ";
});
return value;
}
return (!inItem ? this.defaultValue : (!this.field ?
this.value : dereference(inItem, this.field)));
}
}, document.createElement('div'));
. . .
}
|
选择标签容器的第三个标签将会显示 Champions since 2000 矩阵查看器,冠军球队背景为黄色,如图 4 。
图 4. 矩阵查看器用黄色背景显示冠军
XML 中的样式 是样式元素中已定义的样式的引用;它可以通过标记加注定义;或根本不存在。一个样式元素 是一组 attribute=<value> 对,每个指定了样式属性的值。一个样式可以有任意个属性:背景颜色、边框颜色、边框宽度、边框样式、字体颜色、字体集和字体大小。
清单 9 显示的是 Champions since 2000 XML 中的片段,其中 style 用 background 属性标记加注。
清单 9. 图 3 中显示的 XML 摘录
<cell id="22">
<cellDefinitionRef href="#cellDef" />
<location>
<columnRef href="#02" />
<rowRef href="#20" />
</location>
<contents>
<listItems>
<listItem href="http://en.wikipedia.org/wiki/New_England_Patriots">
<styleAlternative>
<style>
<background>yellow</background>
</style>
</styleAlternative>
<contents>New England Patriots</contents>
</listItem>
</listItems>
</contents>
</cell>
|
我们通过使用 applyStyle 函数标记存储中的数据来应用样式。(我们知道不将数据过滤就在网格中显示有安全风险,但此例中,SA/XT 矩阵查看器的数据来自安全的数据源。)
运行时,还会看到矩阵查看器还有其他一些特性:
- 打印按钮,在图 3 和 4 中屏幕右上方,使用网格的数据存储生成与显示的矩阵对应的 HTML 表格,从而浏览器的打印函数可以自动排列打印页面。
- 我们实现了内容单元格排序。排序使用的是自定义的比较器接口实现,它由 Dojo API 提供。该函数根据单元格中的文本将列单元格排序(排序不包含标记)。如果单元格为空,它以空字符串处理。
矩阵查看器模式和代码也处理消息,尽管在本例中不包含这部分。消息可以添加到一个矩阵、一个部分或一组单元格的消息列表中,用来传达警告或通知用户有错误。
据上所述,矩阵查看器是用来在 web 浏览器中显示 SA 矩阵,这在以前只能用在 SA 桌面应用程序中。SA/XT 矩阵查看器支持添加到 SA 库中的各种用户定义矩阵信息检查。每个矩阵都是由两个 SA 报表相交生成。SA/XT 浏览器显示了 Matrices 节点下的矩阵定义,如图 5 所示。
图 5. SA/XT 浏览器显示 Matrices 节点下的矩阵定义
当用户点击 Matrices 节点下的某一矩阵定义链接,就会加载该矩阵的矩阵查看器。选中矩阵的 ID 传递到矩阵查看器中。然后矩阵查看器调用 Matrix Adaptor,它是接收矩阵 ID 的服务器脚本。图 6 演示了一个样例。
图 6. SA/XT Matrix Viewer 架构
在 Rational System Architect 中,由三个组件来定义一个矩阵:
- 一个报表定义行集合
- 一个报表定义列集合
- 由行和列项的相互关系或报表定义相应行和列项的相交单元格项
Matrix Adaptor 处理各种报表,交汇数据,根据结果生成 Matrix XML,再由矩阵浏览器解析并显示。
图 7 显示了一个通用矩阵,它用于称为 SWOT Assessment (Strength/Weakness/Opportunity/Threat) 的 Enterprise Architecture 中。它用于区分某些态势对一个机构完成某个经营指标的影响。这个虚构的样例来自 IBM Rational System Architect 的样例库,其中还包括虚构的 Chelsea Hotels。它演示了一些影响样例 — 包括外部和内部事件 — 对 Chelsea Hotels 经营指标的影响。为了显示经营指标和态势,交叉单元格显示了SWOT 分类,它表示正面或负面影响。
图 7. SA/XT Matrix Viewer SWOT 评估架构
这里有一些有趣的设计特性,它不是之前矩阵样例的一部分。单元格内容,包括文本内容和颜色,都在矩阵中重用。为了能够重用,并不让文本和样式值重复,XML 顶部的 XML 代码片段专门指定可重用的值和样式。这既节约了整个 XML 的大小,也让我们可以在将来重新编辑。
在以下清单 10 代码中,您将看到演示重用的样例。首先,styles 用于定义可重用的绿色背景。然后定义了名为 SWOT Assessment 的类型,说明此后的单元格是 SWOT Assessment 类型的。在定义 SWOT Assessment 的 cellDefinition 中,定义了一组 choices,表示单元格值不是公开的文本值集合,而是一个列表值。对于 Strength 选项,选择了前面的绿色背景选项 style1。在 id 为 4777 和定义类型为 SWOT Assessment 的单元格中,选项值为 Strength。
清单 10. 重用样式定义
<matrix id="4558" xmlns="urn:SAXT-Matrix">
<name>SWOT Assessments (Influences on Objectives)</name>
…
<styles>
<style id="style1">
<background>#32FF32</background>
</style>
…
</styles>
<types>
<type id="699">
<label>SWOT Assessment</label>
</type>
…
</types>
<cellDefinitions>
<cellDefinition id="cellDef1">
<cellTypes>
<typeAlternative>
<typeRef href="#699" />
</typeAlternative>
</cellTypes>
<choices>
<choice id="Strength">
<styleAlternative>
<styleRef href="#style1" />
</styleAlternative>
<contents>Strength</contents>
</choice>
…
</choices>
…
</cellDefinition>
</cellDefinitions>
…
<cells>
<cell id="4777" href="getpage.aspx?DDID=4777">
<cellDefinitionRef href="#cellDef1" />
…
<contents>
<stringTextValues>
<valueRef href="#Strength" />
</stringTextValues>
</contents>
</cell>
…
</cells>
</matrix>
|
您已经了解如何创建基于 Dojo 的矩阵浏览器,以及如何通过编程方式将 XML 数据输入转换成 Dojo 网格可认的数据结构。希望您从下面的 下载 表下载 developerWorksMatrixViewer 样例,并运行一遍。
我们是在 IBM Rational System Architect XT 中使用矩阵查看器。如果您的应用程序中也需要动态创建数据列和行,并动态显示自定义样式的数据,可以在您的应用程序中使用这些思路和实现方法。
| 描述 | 名字 | 大小 | 下载方法 |
|---|---|---|---|
| 基本矩阵和矩阵查看器样例1 | developerWorksMatrixViewersExamples.zip | 10KB | HTTP |
注意:
- zip 中有两个样例:基本矩阵和矩阵查看器。
学习
- 阅读本系列第 1 部分 “创建并置表,第 1 部分:使用 Flex 创建 JTable”,这篇文章讲解了如何动态创建表的列及修改表的内容。
- 探索 Dojo toolkit,Dojo Foundation 的开源 JavaScript 库。
- 查看 Rational System Architect 概述和演示。
- 了解更多关于 Rational System Architect XT 的内容,这是基于 web 的企业架构解决方案,为企业提供业务和变革分析。
-
developerWorks Web development
专区:通过专门关于 Web 技术的文章和教程,扩展您在网站开发方面的技能。
-
developerWorks Ajax 资源中心:这是有关 Ajax 编程模型信息的一站式中心,包括很多文档、教程、论坛、blog、wiki 和新闻。任何 Ajax 的新信息都能在这里找到。
-
developerWorks Web 2.0 资源中心,这是有关 Web 2.0 相关信息的一站式中心,包括大量 Web 2.0 技术文章、教程、下载和相关技术资源。您还可以通过 Web 2.0 新手入门 栏目,迅速了解 Web 2.0 的相关概念。
获得产品和技术
- 获取 Dojo 代码。
- 下载 IBM 产品评估试用版软件 或 IBM SOA 人员沙箱,并开始使用来自 DB2®、Lotus®、Rational®、Tivoli® 和 WebSphere® 的应用程序开发工具和中间件产品。
讨论
- 现在就创建 developerWorks 社区配置文件 并创建关于 Dojo 的 查看列表。与 developerWorks 社区 建立连接、保持连接。
- Web developers,在 Web 开发小组分享您的经验和知识。
- 分享您所知道的: 加入关注某个 web 主题的 developerWorks 小组。
- Roland Barcia 在其博客讲述 Web 2.0 及中间件。
- 看看 developerWorks 成员的 共享书签和主题。
- 快速获取答案:访问 Web 2.0 Apps 论坛。

Marian Bloch 是 IBM Software Group, Rational 的软件开发人员。她最近的项目包括 SA/XT web 应用程序及 IBM Rational System Architect 产品套装的其他应用程序。Marian 有 15 年企业架构建模工具经验。

Matt Callery 是位于纽约 Hawthorne 的 IBM Thomas J. Watson Research Center 的软件工程师。在为 IBM 工作的 21 年间,Matt 曾任职于 IBM 的 Global Services、Internet、Software 和 Research 部门。最近的 14 年中,他专注于 Web Application Development,他既为外部客户做过项目,也支持过 IBM 的 Software 和 Services 部门。


