使用 XForms 和 formsPlayer 构建天气 Web 服务客户端






3.63/5 (12投票s)
使用 XForm 轻松快速地构建 Web 服务客户端
引言
Web 服务是一项充满潜力的技术。 我们能够构建自己的自定义应用程序,与谷歌搜索、亚马逊书店、天气预报、日记、旅行计划等等进行交互,这当然对我们开发者来说是一个令人兴奋的想法。
但是,一个大问题是,实现这一目标的最常见方式要么是在服务器上聚合 Web 服务,然后将 HTML 用户界面交付给用户,要么使用带有 SOAP 向导的开发应用程序,该应用程序生成与 Web 服务交互的静态用户界面。
这两种解决方案的问题在于,它们大大提高了玩转 Web 服务的门槛——您要么需要一台服务器及其所有相关软件,要么至少需要一个昂贵的开发环境。然后还有一个更大的问题是,您想出的任何解决方案只能由与您具有相同编程环境的人进一步开发。
XForms
XForms
[1] 通过提供一种开放标准语言,使我们能够与 Web 服务进行交互,从而解决了这个问题。 使用非专有语言可以让我们共享解决方案,而无需要求我们都运行相同的开发环境。
更重要的是,由于 XForms
处理器可以为您可以想到的任何平台构建,因此生成的代码具有极高的可移植性。
但我认为最终最重要的优势是,XForms
是一种声明性语言——这意味着我们可以非常快速地构建和测试复杂的解决方案。 在本教程中,我们将构建一个与天气服务交互的程序,代码量不到 50 行标记——包括样式表规则,并且没有隐藏的“代码后置”!
简而言之,可以想象 Java 虚拟机的好处……但没有其中的麻烦。
开发环境
要跟随本示例,您真正需要的是一个简单的文本编辑器,例如记事本,以及一个 XForms
处理器。 我在这里使用的是 formsPlayer
[2],因为它是一个 Internet Explorer 6 的插件,因此可以非常方便地将普通 HTML 与表单混合使用,但您也可以尝试其他,例如
- X-Smiles [3]
- Novell Technology Preview [4]
- Chiba [5]
- DENG [6]
天气 Web 服务
在此示例中,我们将访问天气报告 Web 服务。 我们将使用的服务已在 CodeProject [7, 8] 的其他几个示例中提及,并来自 EJSE [9]。
步骤 1 - 一个简单的表单
我们将要做的第一件事是创建一个简单的 XForm
,它从 Web 服务中将邮政编码 02852 的天气报告加载到 DOM 中。该表单还将显示地点名称和当前天气预报。
表单的代码由模型和用户界面组成。模型包含一个 DOM 和一个初始化它的天气预报的指令,而 UI 有几个输出控件,分别连接到通用天气预报和对应于邮政编码的地点。
当我们编写表单时,我们需要做的第一件事是建立所有需要的命名空间。 显然,我们需要一个用于 XForms
的,但我们也需要一个用于 XHTML(它托管我们的 XForms
元素)的,以及一个用于天气 Web 服务的。
<?xml version="1.0" encoding="utf-8"?>
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xforms="http://www.w3.org/2002/xforms"
xmlns:wr="http://ejse.com/WeatherService/"
>
接下来,我们需要加载 formsPlayer
来处理 XForms
元素。如果您使用的是 X-Smiles 或 Novell Technology Preview,则不需要此步骤,但由于它们会忽略此标签,所以不会造成损害——换句话说,此表单仍然是跨平台的。
<head>
<object id="formsPlayer"
classid="CLSID:4D0ABA11-C5F0-4478-991A-375C4B648F58">
formsPlayer has failed to load! Please check your installation.
</object>
<?import NAMESPACE="xforms" IMPLEMENTATION="#formsPlayer" ?>
现在,我们可以建立数据模型。 在数据模型中,我们只有一个 XML 文档,该文档被初始化为对天气 Web 服务进行九天天气预报请求的结果(使用 HTTP GET
方法)。
<xforms:model>
<xforms:instance
src="http://ejse.com/WeatherService/Service.asmx/
GetExtendedWeatherInfo?zipCode=02852"
/>
</xforms:model>
</head>
来自 Web 服务 的结果由九个元素(每个天气预报日一个)组成,前面有一个包含有关地点、报告上次更新时间、天气预报等信息的元素。
<ExtendedWeatherInfo
xmlns="http://ejse.com/WeatherService/">
<Info>
<Location>North Kingstown, RI</Location>
...
</Info>
<Day1>
...
</Day1>
<Day2>
...
</Day2>
.
.
.
<Day9>
...
</Day9>
</ExtendedWeatherInfo>
为了能够确认一切正常工作,我们将构建一个简单的 UI 来显示 Info
块中的一些信息。
<body>
<xforms:group ref="wr:Info">
<xforms:label>Current Conditions</xforms:label>
<xforms:output ref="wr:Location">
<xforms:label>Location:</xforms:label>
</xforms:output>
<xforms:output ref="wr:Forecast">
<xforms:label>Forecast:</xforms:label>
</xforms:output>
</xforms:group>
</body>
</html>
如果您已解压 zip 文件并安装了 XForms
处理器,则打开文档 fP-and-weather-ws-step-1.html,您应该会看到类似以下内容:
如果您想在继续之前玩弄这个简单的表单,这里是 Info
元素的一个典型内容:
<Info>
<Location>North Kingstown, RI</Location>
<IconIndex>-1</IconIndex>
<Temprature>69°F</Temprature>
<FeelsLike>69°F</FeelsLike>
<Forecast>Partly Cloudy</Forecast>
<Visibility>6.0 miles</Visibility>
<Pressure>29.95 inches and rising</Pressure>
<DewPoint>64°F</DewPoint>
<UVIndex>0 Low</UVIndex>
<Humidity>84%</Humidity>
<Wind>From the West at 5 mph</Wind>
<ReportedAt>Providence, RI</ReportedAt>
<LastUpdated>Wednesday, July 21, 2004,
at 6:51 AM Eastern Daylight Time.</LastUpdated>
</Info>
更改任何 @ref
值,或添加一些新的 output
,看看会发生什么。
步骤 2 - 样式
在添加更多信息之前,让我们让表单更容易阅读。 由于 XForms
是建立在其他 W3C 标准之上的,所以您会了解到我们可以使用 CSS 来设置我们的输出样式,这并不会让您感到惊讶。
我们要做的第一件事是去除所有边距,并设置默认字体。 我们将这段代码插入到 head 中,放在 model
元素之后。
</xforms:model>
<style>
html, body
{
margin: 0px;
padding: 0px;
}
body
{
font-family: "Trebuchet MS", Verdana, Helvetica, sans-serif;
}
接下来,我们为所有 group
元素创建一个规则。
xforms\:group
{
float: left;
border: 3px silver window-inset;
padding: 5px;
background-color: silver;
}
最后,我们为天气预报中的信息添加一些规则。
.location, .forecast
{
display: block;
font-size: xx-small;
}
</style>
</head>
然后,我们可以通过修改 UI 来使用这些样式名称,如下所示:
<xforms:output ref="wr:Location" class="location">
<xforms:label>Location:</xforms:label>
</xforms:output>
<xforms:output ref="wr:Forecast" class="forecast">
<xforms:label>Forecast:</xforms:label>
</xforms:output>
最终的显示现在将是:
步骤 3 - 重复数据
现在我们知道我们的表单可以工作,并且它开始看起来好一些了,让我们获取九天预报的数据。我们将利用 XForm
的 repeat
元素,它允许我们指定一个模板,无论有多少项,都将用于渲染节点集中的每个项。
在我们的 repeat
中需要指定的第一个内容是我们想要处理的节点列表。正如您在开头所见,预报的元素命名是唯一的(Day1
、Day2
等),所以我们不能使用元素名称作为选择器。但是,每个预报都有一个子元素 Day
,所以我们可以使用它来唯一标识我们的 nodeset
。在 group
的结束元素之后添加以下内容:
</xforms:group>
<xforms:repeat nodeset="*[wr:Day]">
[template goes here]
</xforms:repeat>
</body>
我们现在有一个 repeat
,它将遍历一个包含所有具有 Day
子元素的节点的节点集。接下来,我们需要指定用于这些节点之一的模板。一个典型的单日预报条目是:
<Day1>
<Day>Thu</Day>
<Date>Jul 22</Date>
<IconIndex>30</IconIndex>
<Forecast>Partly Cloudy</Forecast>
<High>80°</High>
<Low>65°</Low>
<PrecipChance>20 %</PrecipChance>
</Day1>
所以,为了开始——并确保我们的 repeat
工作正常——让我们只输出 Day
。不过,我们将增加一个技巧——当用户将鼠标悬停在 Day
值上时,我们将渲染一个从 Date
派生的提示。repeat
模板现在如下所示:
<xforms:repeat nodeset="*[wr:Day]">
<xforms:output class="day" ref="wr:Day">
<xforms:hint ref="../wr:Date" />
</xforms:output>
</xforms:repeat>
请注意,所有 XPath
语句都有一个上下文,在此示例中,hint
的上下文是 wr:Day
——因此,在 wr:Date
之前需要“..
”。我们还需要为类 ‘day
’ 设置一些样式。
.location, .forecast
{
display: block;
font-size: xx-small;
}
.day
{
color: blue;
font-weight: bold;
}
</STYLE>
表单现在看起来应该像这样:
既然我们确信一切正常,我们可以根据需要修改 repeat
模板。虽然我们不限于仅使用 @ref
回显实例文档中的数据。在下一个片段中,我们可以看到如何使用 output
上的 @value
来调用函数,并连接两个 string
值——即低温和高温值。
<xforms:repeat nodeset="*[wr:Day]">
<xforms:output class="day" ref="wr:Day">
<xforms:hint ref="../wr:Date" />
</xforms:output>
<xforms:output class="tempRange" value="concat(wr:Low, '-',
wr:High)"/>
</xforms:repeat>
相关的样式更改是:
.day
{
color: blue;
font-weight: bold;
display: block;
}
.tempRange
{
font-size: smaller;
}
添加温度范围后,表单应如下所示:
步骤 4 - 渲染图像
这个简短教程的最后一步是显示与天气预报关联的图像。XForms
1.0 不支持基于实例数据的图像渲染,但这将在即将推出的 XForms
1.1 中包含。但是,formsPlayer
提供了一种执行此操作的机制,即使用嵌套标记。我们将在此处使用该功能,并考虑到当一种平台无关的指定图像的方式可用时,我们需要对其进行更改。
与之前一样,标记的位置在 repeat
模板中。这次,我们将使用 Web 服务数据中的 IconIndex
元素,并构建一个 HTML img
元素,该元素具有指向 EJSE Web 服务服务器上的图像的 URL。我们的模板现在应如下所示:
<xforms:repeat nodeset="*[wr:Day]">
<xforms:output class="day" ref="wr:Day">
<xforms:hint ref="../wr:Date" />
</xforms:output>
<xforms:output
class="image"
value="concat(
'<img src="http://www.ejse.com/WeatherService/images/52/',
wr:IconIndex,
'.gif" />'
)"
>
<xforms:hint ref="wr:Forecast" />
</xforms:output>
<xforms:output class="tempRange"
value="concat(wr:Low, '-', wr:High)"/>
</xforms:repeat>
请注意,我们还添加了一个 hint
,以便将鼠标悬停在图像上时,我们会获得天气预报。
我们需要添加一个进一步的样式规则,使我们的图像成为“block
”,同时我们在编辑 CSS 时,让我们稍微调整一下。
.day, .location, .forecast, .image
{
display: block;
}
.location, .forecast
{
font-size: xx-small;
}
.day
{
color: blue;
font-weight: bold;
}
我们还需要添加一个规则来控制 repeat
中每个项的样式。这在 XForms
中使用名为 repeat-item
的伪类来解决,尽管 formsPlayer
使用普通类名来实现这一点——但在样式规则中同时包含这两种格式也没有坏处。我们还将使用于“today
”的 group
具有与 repeat-item
相同的样式。
::repeat-item, .repeat-item, xforms\:group
{
float: left;
border: 3px silver window-inset;
padding: 5px;
width: 80px;
height: 140px;
background-color: white;
text-align: center;
}
我们的显示现在应该看起来像这样:
步骤 5 - 品牌
一个额外的步骤是 formsPlayer
特定的,但涉及自定义项目中文档的品牌。这可以通过 model
上的一个额外属性轻松实现,该属性指向一个配置文件,该配置文件包含您想要使用的启动页面和表单控件图标的信息。该文件是加密的,并且仅适用于特定 URL,在许可 formsPlayer
[10] 时获得。请注意,这不会改变 formsPlayer
的行为,并且如本文所示的表单,无论是否有许可证,都可以在 formsPlayer
上运行。这使其成为开发基于 Web 服务的应用程序的绝佳平台。
如果您购买了许可证,您可能会发现在测试期间,您会想避免反复将应用程序部署到 Web 服务器。另一种选择是获取完全许可版本的 XFormation
[11],它允许完全控制 formsPlayer
使用的品牌。在下面的屏幕截图中,我们可以看到 XFormation
正在渲染我们刚刚完成的表单,但没有任何品牌。
结论
如果应用程序或表单对 XML(例如使用 Web 服务的表单)有很强的依赖性,那么 XForms
就是首选语言。其声明性语法使得构建、测试和部署应用程序比传统技术快得多。随着越来越多的 XForms
处理器在更多平台上得到开发,您现在开发的任何应用程序和表单都将能够在越来越多的环境中运行。