for each (var p in x.person) {
if (p.height.@measure=="metric")
p.height=metricToImperial(p.height);
}
print (x);
這裡是輸出內容:
<people>
<person gender="male">
<name>Ant</name>
<hair>Shaggy</hair>
<eyes>Blue</eyes>
<height measure="imperial">
<feet>5</feet>
<inches>11</inches>
</height>
</person>
<person gender="male">
<name>Paul</name>
<hair>Spiky</hair>
<eyes>Grey</eyes>
<height measure="imperial">
<feet>5</feet>
<inches>12</inches>
</height>
</person>
</people>
E4X 中的 XML 命名空間(Namespace)
如果您是一名 XML 高手,那麼此時您可能想知道如何使用該語法來管理 XML 命名空間。這裡有三種方式來實現該操作:
首先,您可以使用內嵌的 XML 語法:
var soapMsg = <s:Envelope XMLns:s="http://www.w3.org/2003/05/soap-envelope"/>;
print(soapMsg.namespace());
http://www.w3.org/2003/05/soap-envelope
第二個方法是在創建元素之前設置缺省的 XML 命名空間:
default XML namespace = new Namespace("http://www.w3.org/2003/05/soap-envelope");
您可以將它設置為空字符串,以便對該缺省的命名空間進行重新設置,例如:
default XML namespace = ""
最後一種方法是使用 :: 運算符
var f = new Namespace("http://fremantle.org");
soapMsg.Body.f::GetStockQuote="IBM";
print(soapMsg);
<s:Envelope XMLns:s="http://www.w3.org/2003/05/soap-envelope">
<s:Body>
<frem:GetStockQuote XMLns:frem="http://fremantle.org">
IBM
</frem:GetStockQuote>
</s:Body>
</s:Envelope>
E4X 所具有的一個明顯的優點是它完全支持 XML,包括排序功能。許多從 XML 文檔到相應編程語言對象的直接映射僅僅支持符合常規對象語義的 XML 語義子集——因此就失去了不僅能夠表示對象而且還表示文檔的功能。但是對本文來說,它是不合適的,只要簡單查看一下該規范就可以看出,E4X XML 對象具有的內置功能能夠對 XML 元素進行細致准確的排序。
在 XML 中使用 Javascript 表達式
在轉向 Web 服務之前,我們向您介紹的最後一個內容——使用大括號“{}”。以上我們介紹了“內嵌的”XML。E4X 也允許您重新進入 JavaScript 環境,並且可以包括了計算後的表達式值。例如:
var num = 36;
var p = <paul><age>{num}</age></paul>
print(p);
<paul>
<age>36</age>
</paul>
到目前為止,我們已經介紹了 E4X 的基礎知識,下面我們就可以使用這些基本知識進行以下操作。
使用 E4X 來調用 Web 服務
本節中,我們將描述如何在以下兩個環境中使用 E4X:
1. 使用 XMLHttpRequest 的 Mozilla 1.8
2. Java/Rhino
您可以很容易地在浏覽器中使用 E4X 來調用 Web 服務。但是這裡存在問題!到目前為止,唯一的支持 E4X 的浏覽器是 Mozilla 1.8 的專業版。不過我們並沒有將其作為一種可移植的跨浏覽器的解決方案來推薦,以下的實例演示了 E4X 如何以一種簡單的方式來調用 Web 服務。在下一節中,我們將查看運行在 Rhino JavaScript 引擎中的另一種方法。
AJax
該樣本實例顯示了向 SOAP 服務器發送和接收 SOAP 消息的浏覽器。為了實現該操作,我們通過 XMLHttpRequest 對象來使用 E4X 。這個對象非常的有用,而且 Mozilla 和 Internet Explorer 浏覽器都支持它,它允許運行在浏覽器內部的腳本語言在後台中生成 HTTP 請求。實際上,這就是為什麼 Google 的 GMail 能做到任何事情的原因。這種架構最近被命為 Asynchronous JavaScript+XML(AJax)。
從根本上來說,AJax 的目的是要通過一種比標准 Html 和 HTTP 的“頁面”模型更為靈活的方式與服務器進行交互,以此來提高 Web 頁面的響應能力和可用性。有關這方面一個很好的樣本是 Google Maps beta,它明顯地比以前的映射 Web 站點更具交互性。
令人鼓舞的是,根據新聞報道,結合了 E4X 的 AJax 的性能更優!我們將向您展示浏覽器應用的兩種版本。第一個版本演示了交互操作,而第二個版本隱藏了 Web 頁面上的按鈕和內部的工作過程,以此來展示交互性和異步性。
浏覽器的安全性
為了演示浏覽器的安全性,我們使用了 xmethods.Net 上可用的標准 Web 服務。但是,這裡還存在一個問題,因為一般來說,浏覽器的安全性規則不允許腳本程序或者 Java applet 程序創建網絡連接,除非是與生成該頁面的服務器建立網絡連接。否則,您需要有一個監控頁面,它將您的按鍵操作“復制”到另外一個服務器。
但是您可以避開這種操作。為實現該操作,您需要進行兩步。首先,您必須啟用 Mozilla 配置中的用於腳本程序的升級特權。(假定您已經下載並安裝了 Mozilla 1.8 beta)。
在該浏覽器的地址欄中輸入 about:config,然後將 signed.applets.codebase_principal_support 的值從 false 更新為 true。(出於安全性考慮,請記得在完成全部操作後設回原值。)
然後在腳本程序中,您可以請求使用升級特權。當該腳本語言運行時,將會提示用戶使用這些特權。代碼行為:
netscape.security.PrivilegeManager.enablePrivilege( "UniversalXPConnect UniversalBrowserAccess");
其它的選擇就是將服務和 Web 頁面部署到諸如 IBM® WebSphere® Application Server 或者 Tomcat 之類的 Web 應用程序服務器中。例如,這種方式適用 apache Axis 和 Axis 自帶的缺省股票報價機樣本實例。
股票報價客戶端樣本
該腳本程序屬於 stockclIEnt.html 的一部分。如果您從本文下載了 ws-AJax1code.zip 文件,將其中的 zip 內容解壓,然後使用 Mozilla 打開 stockclIEnt.Html
為了對其進行驗證,首先單擊 Update URL。該操作通過使用 XMLHttpRequest 對象從 http://services.xmethods.Net/soap/urn:xmethods-delayed-quotes.wsdl(或者您在 WSDL 框中鍵入的任意 URL)獲取 WSDL 文件,然後使用 E4X 從那裡獲取端口地址 URL。現在單擊 Send,您將會看到 SOAP 請求被填寫了。一兩秒鐘之後,此 SOAP 響應應該同結果字段一起被更新。我們查看一下這些代碼。
股票報價客戶端的腳本程序
該腳本程序帶著對 IBM 的股票價格的 request 調用指定的URL。如果您正在使用 Axis 服務器,那麼我們建議使用股票行情自動收錄機符號 XXX,這是一種特殊的符號——部署的服務將總是返回一個固定的響應用於該收錄機,而不是產生 Web 請求來得到真正的股票價格——因此使用該符號進行測試會好些。
您必須完成的第一個操作就是定義您希望使用的 E4X:
<script type="text/Javascript;e4x=1">
當您按下 Send 按鈕時,該腳本程序顯示如下:
var s = new Namespace(
"s",
"http://schemas.XMLsoap.org/soap/envelope/");
var envelope = <s:Envelope XMLns:s={s}/>;
envelope.s::Body="";
var body = envelope.s::Body;
該操作對任何的 SOAP 請求都是通用的。它只是簡單地創建了一個 SOAP 信封,而沒有包括任何消息體。該操作的一個等價實現方式如下所示:
var envelope =
<s:Envelope xmlns:s="http://schemas.XMLsoap.org/soap/envelope/">
<s:Body/>
</s:Envelope>
但是,前面的代碼會容易些,而且也為您提供了指向主體元素的指針。
下一步是要創建消息的主體:
var x = new Namespace("x","urn:XMLtoday-delayed-quotes");
body.x::getQuote = <x:getQuote XMLns:x={x}/>;
最後,你必須添加正確的符號:
var symbol = document.getElementById("symbol").value;
var getQuote = body.x::getQuote;
getQuote.symbol=symbol;
現在您已經有了一個完全成形的 SOAP 請求消息。如果您想要測試該消息信封,那麼需要按照以下操作:
<s:Envelope xmlns:s="http://schemas.XMLsoap.org/soap/envelope/">
<s:Body>
<x:getQuote XMLns:x="urn:xmethods-delayed-quotes">
<symbol>XXX</symbol>
</x:getQuote>
</s:Body>
</s:Envelope>
為了發送它,你必須使用 XMLHTTPRequest 對象。我們創建了一個簡單的輔助函數,以支持使用 XMLHttpRequest 對象來調用使用 E4X 的服務。此 execService 函數不僅支持異步方式而且也支持同步方式。
function execService(url, XML, callback) {
var xmlhttp = new XMLHttpRequest();
var async=false;
if (arguments.length==3) async=true;
XMLhttp.open("POST", url, async);
XMLhttp.setRequestHeader("SOAPAction", "\"\"")
xmlhttp.setRequestHeader("Content-Type", "text/XML")
if (async) {
var f = function() {
if (XMLhttp.readyState==4) {
callback(new XML(XMLhttp.responseText));
}
}
XMLhttp.onreadystatechange = f;
}
xmlhttp.send(XML.toString());
if (!async) return new XML(XMLhttp.responseText);
}
下面我們來詳細地看看這些代碼。首先,這些代碼支持兩種調用方式。您可以使用其中一種:
XML execService(String url, XML envelope);或者void execService(String url, XML envelope, function callback);
在這種情況下,回調函數應該是 void callback(XML x)。
於是您可以使用該函數直接調用 XML 服務,並且等待響應,或者您也可以傳送一個函數,使用 XML 響應消息調用該函數。
該函數基於參數的數量來決定它是異步還是同步(3 是異步),然後簡單地使用 XMLHttpRequest 對象以 POST 請求方式來把 XML 消息放到 HTTP 請求信息,並把請求發送到指定的 URL。