簡介 VoiceXML是一種用來創建可以通過電話訪問的內容的基於XML的編程語言,這樣的內容不僅僅是具有互聯網訪問功能的移動電話可以訪問,普通的電話也照樣可以訪問這些內容。Html使用圖形用戶界面訪問網站的內容,而VoiceXML則通過語音界面訪問內容,其中的語音和撥號盤代替了傳統的顯示器、鍵盤和鼠標。對VoiceXML及其工作原理進行詳細的介紹不在本文的范圍之內,有關這方面的知識請參與相關資料。
一個簡單的例子 為了說明通過電話訪問現有的互聯網內容是如何簡單,我們將使用Perl建立一個簡單的CGI腳本文件,獲取一個包含CPAN最近上傳內容的文件,然後將文件轉換為VoiceXML,以便用戶能夠通過VoiceXML網關在電話上訪問這些內容。 use strict; use XML::XPath; use LWP::UserAgent; 加載必要的模塊後,在腳本程序的開始,我們創建新的HTTP::Request和 LWP::UserAgent對象,然後調用LWP::UserAgent的simple_request方法為RSS文件請求遠程服務器。 my $news_url = 'http://search.cpan.org/recent.rdf'; my $request = HTTP::Request->new('GET', $news_url); my $ua = LWP::UserAgent->new(); my $response = $ua->simple_request($request); 發出請求後,我們將開始輸出VoiceXML。首先創建vxml root元素和包含一個block元素的表格。在block元素中放入一個audio元素,告訴用戶在RSS文件處理過程期間需要耐心地等待,然後用一個goto元素告訴VoiceXML浏覽器跳到當前文檔中標有headlines的小節。 print QQ*
<vXML> <form id="greeting"> <block> <audio> Please wait while I process the c pan news feed. </audio> <goto next="#headlines"/> </block> </form> *; 然後我們將對response對象進行測試,確保我們已經收到了遠程的RSS文件。如果已經收到了遠程文件,則創建一個新的XML::XPath實例,並將response對象的內容小節傳送給它進行解析。如果在請求文件或在解析返回的內容時出現錯誤,則將出錯的信息存儲在$error中以供以後分析用。盡管封裝對XML::XPath最初調用的eval塊增加了一些系統開銷,但在解析過程出現錯誤時,它能夠使我們很“體面地”退出程序,如果沒有它,解析出現錯誤將使腳本意外地結束。 my ($error, $xp); if ($response->is_success) { eval { $xp = XML::XPath->new(XML => $response->content); $xp->find('/'); }; $error = 'Error parsing RSS file ' . $@ if $@; } else { $error = 'Remote server returned ' . $response->message(); } 如果出現錯誤,腳本則會向用戶返回一個描述錯誤的audio消息,掛斷當前用戶的連接,並關閉腳本。 if ( defined($error) ) { print QQ* <form id="headlines"> <block> <audio> I'm sorry. The following error occurred while fetching the headlines file. $error Please try again later. </audio> <disconnect/> </block> </form> </vXML> *; } 如果RSS文件的獲取和解析過程都沒有出現錯誤,我們將創建一個新的form元素,然後,利用封裝在block中的一個audio元素,通知用戶解析已經成功,准備收聽他所需要的信息。 else { print QQ* <form id="headlines">
<block> <audio> The RSS file has been fetched and processed successfully. The following modules have recently been up loaded to c pan. </audio> </block>
<block> *; 然後,我們在一個循環中處理RSS文檔中的所有item元素。對於每一個item元素我們都輸出一個相應的audio元素,讓VoiceXML文檔使用每個item元素title子元素的值作為需要輸出的文本內容。 foreach my $news_item ($xp->findnodes('//item')) { print "<audio>" . $news_item->findvalue('title') . "\n"; } 最後我們告知用戶整個名單已經讀完了,並歡迎他明天繼續撥打,然後斷開連接並關閉VoiceXML文檔。 print QQ* <audio> This completes the latest c pan up loads. Please call again tomorrow. </audio> <disconnect/> </block> </form> </vXML> *; } 盡管這一段腳本並沒有什麼實際的用處,但可以考慮一下我們在這一段腳本中完成的任務。在短短的沒有幾行的腳本中,我們從遠程的網站上取出了所需要的資源,並提取出我們關心的內容,並使這些信息可以從全世界的任一部電話上接聽。
創建動態的VoiceXML應用 盡管上面的例子揭示出通過電話提供互聯網網站內容和服務的可能性,但用戶和VoiceXML應用之間的“對話”還太缺乏交互性。幸運的是,VoiceXML也提供了一些專門用來接收用戶輸入的元素。另外,象Html表格那樣,VoiceXML表格也可以用來接收通過標准的HTTP GET和POST方法向服務器傳送的數據。 在下面的例子中,通過創建一個很小的講述“神奇的Oracle”故事的應用程序,我們根據使用POST方法輸入的數據創建了一個動態的VoiceXML文檔。為了使程序簡單明了,我們將把程序分為二部分:一個純文本的包含獲取用戶輸入表格的VoiceXML文檔和動態的、由CGI創建的對這些問題的回答進行規格化的文檔。 首先,我們來創建這個表格。在表格的開始處是一個問候語,只有用戶在第一次連接時才會聽到它。
<vXML> <form id="greeting"> <block> <audio> Thank you for calling the mystic Oracle! </audio> <goto next="#main_query"/> </block> </form> 然後,我們將開始設計主表格。這個表格只包含一個名字為query_type的字段,它的用途是獲取用戶的問題。我們需要特別注意grammar元素,它使VoiceXML應用開發人員能夠精確地確定給定字段能夠接收什麼類型的輸入。例如,在我們的例子中,如果用戶的問題中含有“career”、“job”、“boss”、“coworker”或“department”等詞匯,query_type字段的值勤將被設置為“career”。 <form id="main_query"> <fIEld name="query_type"> } [career job boss coworker department] {} [family husband wife mother father son daughter] {} ] ]]> </grammar> prompt元素通知VoiceXML網關向用戶朗讀一段文字,並等待響應。在本例中,如果用戶提問的問題中包含上面一段腳本中的grammar元素中定義的詞匯之一,應用程序就會向用戶表示感謝,並使用POST方法把信息提交給應用程序的CGI部分。submit元素的namelist屬性允許我們指定准備提交當前文檔中的哪個字段或變量。 <prompt> Clear your mind and concentrate on your question. You may ask your question now. </prompt> <filled> <audio>thank you.</audio> </filled> 下面的代碼是一個錯誤陷阱結構,可以使Oracle應用有一個更合理的界面。如果用戶所問的問題中不包含上面的grammar元素中所包含的詞匯,nomatch標記中所包含的文本就會被朗讀出來。reprompt元素使VoiceXML浏覽器返回到所在模塊的開始,並重新朗讀前面的提示。如果用戶沒有提問問題,系統將根據每個noinput的count屬性定義的順序每次朗讀一個noinput元素。如果三次提示後用戶仍然沒有提問問題,應用程序將掛斷與用戶的連接。 <nomatch> The mystic Oracle can only answer questions about romance, career, or family matters. Please try again. <reprompt/> </nomatch> <noinput count="1"> I can sense your apprehension. <reprompt/> </noinput> <noinput count="2"> You must say something. <reprompt/> </noinput> <noinput count="3"> Please call back when you are less stressed. <disconnect/> </noinput> 下面的內容是為了結束query_type字段、其父表格和最頂部的vXML元素。 </fIEld> </form> </vXML> 下面我們來創建響應用戶問題的CGI腳本程序。這一腳本程序將接收一個通過POST方法傳送、名字為query_type的字段的參數,query_type的可能的值為romance、career或 family。 use strict; use CGI qw(:standard); my $q = CGI->new(); my $query_type = $q->param('query_type'); 首先,我們將生成一個針對用戶所提問題的比較含糊的答案。 my @intro_phrases = ('My sources say', 'All signs indicate that', 'Search your heart. You know'); my @responses = ('the answer is yes.', 'the answer is no.', 'it is too soon to tell.', 'the outlook is hazy. Please ask again later.'); my $response_text = $intro_phrases[int( rand ( scalar (@intro_phrases) ) )] . ' ' . $responses[int( rand ( scalar (@responses) ) )]; Then we will create the VoiceXML output. Note how the inline Perl variables are used both to include the randomly-generated answer to the caller's question ($response_text) and to create an illusory sense of personalized context by repeating the general type of question that the caller asked ($query_type). 下面我們將創建VoiceXML的輸出。請注意內置的Perl變量━━$response_text和$query_type的使用。 print QQ*
<vXML> <form id="response"> <block> <audio> I sense your consternation. Questions about $query_type can be very troublesome, indeed. $response_text </audio> <goto next="#new_or_exit"/> </block> </form> 作為最後一個功能,我們將讓用戶有機會向mystic Oracle提另一個問題。如果在得到系統的提示後,用戶回答“no”,系統將會禮貌地謝謝用戶並掛斷連接,否則系統將返回到上面文檔中的main小節,用戶將聽到提出新問題的提示。
</form> </vxml> *; 用戶和mystic oracle之間的典型的對話可能如下所示: Oracle: Thank you for calling the mystic oracle! Clear your mind and concentrate on your question. You may ask your question now. Caller: Hmmmm. Should I take the new job I was just offered? Oracle: Thank you. I sense your consternation. Questions about career can be very troublesome, indeed. All signs indicate that the answer is yes. Would you like to ask another question? Caller: Yes, I would. Oracle: Clear your mind and concentrate on your question. ... 結論 VoiceXML不僅僅是互聯網的另一種界面,它可以讓開發人員以一種嶄新和有用的方式擴展現有的互聯網應用,在新的應用開發中,它也能向開發人員提供特有的功能,開發出功能強大的應用。也許你應該能夠想得到,功能和靈活性是需要代價的,VoiceXML網關(將互聯網與電話系統相連、將文本轉換為語音、解釋VoiceXML所需的軟件和硬件)的價格不菲。幸好一些大的VoiceXML網關供應商者向好奇的開發者提供免費的測試環境,因此普通的開發者也能夠滿足自己在這方面的好奇性。