Zmienne
Zmienne w VXML stosują zasady standardu ECMAscript
Można uzyskać dostęp do zmiennych VXML w skrypcie oraz używać zmiennych deklarowanych w dokumencie VXML.
Skrypt jest wykorzystywany do włączania w dokumencie VXML kodu ECMAScript wykonywanego po stronie klienta. Należy pamiętać, że:
- treść skryptu może być umieszczona w pliku zewnętrznym (atrybut src) albo jako wewnętrzna w bieżącym dokumencie VXML (znacznik <script>) - ale nie obydwoma sposobami.
- inaczej niż w HTML, element <script> w VXML nie określa typu, ponieważ może to być wyłącznie ECMAScript.
Nazwa zmiennej musi być unikalna w jej zasięgu i powinna odpowiadać standardowej konwencji nazewnictwa.
Nazwa zmiennej może zawierać dowolny znak z wyjątkiem:
- nie może zaczynać się od `_' (podkreślenie) i kończyć `$' (dolar)
- nie może zawierać znaku `.' (kropka) i `-` (myślnik)
Przykłady błędnych nazw zmiennych:
<var name = "_abc"/>
<var name = "abc$"/>
<var name = "ab.c"/>
<var name = "a-bc"/>
UWAGA: Deklarowanie zmiennej użytkownika za pomocą elementu <var> jest równoważne deklarowaniu zmiennej, wykorzystywanej po stronie klienta, w bloku ECMAscript.
Poniższe deklaracje osiągają dokładnie ten sam cel:
<block>
<var name="myVar" expr="'some value'"/>
<script>
var myVar = 'some value';
</script>
</block>
Deklarowanie zmiennych
Nie trzeba deklarować wcześniej
<form id="F1">
<block>
<assign name="nazwisko" expr="'jan kowalski'"/>
<prompt> hej, tu <value expr="nazwisko"/> </prompt>
</block>
Lecz zasady programowania zalecają, aby zmienna była zadeklarowana przed jej użyciem
(niektóre platformy tego wymagają, brak deklaracji spowoduje błąd error.badfetch)
<form id="F1">
<block>
<var name="nazwisko"/>
<assign name="nazwisko" expr="'jan kowalski'"/>
<prompt> hej, tu <value expr="nazwisko"/> </prompt>
</block>
Lepiej deklarować!
Wszystkie deklarowane zmienne w dokumencie VXML są przetwarzane w porządku sekwencyjnym (nie można inicjować zmiennej zanim wszystkie wcześniej zadeklarowane zmienne zostaną zainicjowane i załadowane do pamięci).
Przykłady użycia zmiennych i wyrażeń:
<var name="wynik"/>
<assign name="wynik" expr="a - b"/>
VoiceXML wykorzystuje język JavaScript (stosuje standard ECMAScript) do przetwarzania danych
JavaScript dostarcza funkcji matematycznych i operacji na znakach, jak również zaawansowanych narzędzi programistycznych (pełna informacja http://www.ecma-international.org/publications/standards/Ecma-262.htm)
Są różnice w implementacji przez różne realizacje VoiceXML
Dwie metody zastosowania JavaScript w VoiceXML:
jako atrybuty znaczników standardu VXML
wewnątrz znaczników <script>... </script>
Wyrażenia JavaScript w atrybutach
VoiceXML ma niewiele własnych cech programistycznych: w zasadzie wykorzystuje język JavaScript, stosuje wiele atrybutów, które pozwalają bezpośrednio wykorzystać wyrażenia JavaScript
Przykład
atrybut `expr' znaczników: <assign>, <field> i <param>
atrybut `cond' w znacznikach <if> i <field>
oczekują wyrażeń JavaScript jako ich wartości
<assign name="result" expr="a - b"/>
Wartość atrybutu `expr' może być dowolnym wyrażeniem JavaScript
Przykład
Do obliczenia pierwiastka kwadratowego, możemy wykorzystać funkcję matematyczną JavaScript:
<assign name="result" expr="Math.sqrt(a)"/>
Wyrażenia JavaScript w skryptach
Zastosowanie znacznika <script> pozwala na wyjście poza proste wyrażenia, wykorzystanie funkcji JavaScript i innych wykonywalnych instrukcji
Aby wstawić kod JavaScript do dokumentu, należy zamknąć ten skrypt znacznikami <script> i </script> (jak w HTML)
Ponieważ VoiceXML opiera się na XML, posiada on różne ograniczenia w możliwości użycia znaków specjalnych
Dla pewności pożytecznie jest zamykać ten kod za pomocą:
<![CDATA[ oraz ]]>
wewnątrz znacznika <script>
Na przykład:
<script>
<![CDATA[
... kod JavaScript ...
]]>
</script>
Bez <![CDATA[ i ]]> należałoby zastąpić niektóre znaki specjalne.
Na przykład:
zamiast < napisać <
zamiast > napisać >
Wszystko upraszcza się, gdy zastosuje się CDATA
<script> może być wykonywany na dwa sposoby, w zależności od miejsca, które zajmuje w dokumencie:
gdy jest na górnym poziomie, tzn. jest zawarty w elemencie <vxml>, wykonywany jest tylko jeden raz, gdy dokument po raz pierwszy jest ładowany do interpretera VXML
(to dobre miejsce do umieszczenia definicji funkcji i inicjacji zmiennych);
gdy jest w elemencie wykonawczym <filled>, <if>, <block>, lub obsługującym wydarzenia, jak <help>, wtedy jest wykonywany za każdym razem, gdy wykonywany jest zawierający go element.
Znaki specjalne w JavaScript
Są 3 znaki (`<', `>' i `&'), których znaczenie różni się w obu językach.
Znak |
Znaczenie w VoiceXML |
Znaczenie w JavaScript |
Sekwencja zastępcza |
< |
Pierwszy znak w tagu (jak w <form> lub </form>) |
Operator arytmetyczny mniejszy niż |
< |
> |
Ostatni znak w tagu |
Operator arytmetyczny większy niż |
> |
& |
Początek jednostki (sposób dostarczenia jakieś informacji) |
Część kilku operatorów dotyczących koniunkcji (AND), jak w & lub && |
& |
Dla wyrażeń JavaScript, które są atrybutem trzeba zastąpić te znaki ciągiem znaków (sekwencją zastępczą).
Przykład
wyrażenie balance < minbalance w tagu <if >
trzeba zapisać:
<if cond="balance < minbalance">
W skryptach JavaScript wewnątrz VoiceXML trzeba unikać tych znaków
Jeżeli kod JavaScript znajduje się wewnątrz elementu <script> kod będzie czytelny, gdy umieścimy go wewnątrz sekcji CDATA, np.:
<script>
<![CDATA[
function factorial(n) {
return (n <= 1) ? 1 : n * factorial(n-1);
}
]]>
</script>
Funkcje
Przykład kalkulatora (pominięto reakcje na zdarzenia) wyznaczającego silnię
Najpierw kod inicjujący:
<?xml version="1.0" ?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml" xml:lang="en-US" >
<!-- <meta name="maintainer" content="you@yourcompany.com"/> -->
Definicja funkcji
<script>
<![CDATA[ - ogranicznik kodu JavaScript
function factorial(n) {
return (n <= 1) ? 1 : n * factorial(n-1);
}
]]> - ogranicznik kodu JavaScript
</script>
Wstawienie tagu <script> bezpośrednio jako dziecko elementu <vxml> powoduje jego jednokrotne wykonanie, gdy dokument jest wprowadzany na początku. Oznacza to, że funkcja nie będzie redefiniowana przy każdym wejściu do formularza
Funkcja nazywa się factorial (silnia). Przyjmuje pojedynczy argument n; wykorzystuje instrukcję return do zwracania wartości do wyrażenia ją wywołującego
Potem następuje definicja formularza, a w nim deklaracja zmiennej lastresult (do przechowywania informacji o ostatnim użyciu funkcji factorial, przypisana wartość początkowa - łańcuch)
<form id=”foo”>
<var name="lastresult"
expr="'This is the first factorial you have computed'" />
<field name="n" type="number">
<prompt> Say a number. </prompt>
Tag filled najpierw informuje o wyniku, wykorzystując trzy tagi <value> z atrybutami expr
<filled>
<prompt>
The factorial of <value expr="n"/> is
<value expr="factorial(n)"/>
<value expr="lastresult" />
</prompt>
a następnie za pomocą tagu <assign> uaktualnia wartość zmiennej lastresult oraz za pomocą atrybutu namelist czyści pole n - to zapewnia zmianę informacji przy następnym przetwarzaniu formularza
<assign name="lastresult" expr=" 'The last factorial you computed was for ' + n" />
<clear namelist="n"/>
</filled>
</field>
</form>
</vxml>
Tutaj operator „+” łączy dwa łańcuchy
Interakcja z tą aplikacją przebiega następująco:
Aplikacja: |
Say a number. |
Użytkownik: |
3. |
Aplikacja: |
The factorial of 3 is 6. This is the first factorial you have computed. |
Application: |
Say a number. |
Użytkownik: |
5. |
Aplikacja: |
The factorial of 5 is 120. The last factorial you computed was for 3. |
Aplikacja: |
Say a number. |
Funkcje i tekst
Funkcje JavaScript mogą operować na fragmentach tekstu (łańcuchach)
To może uprościć dokument, gdy wielokrotnie używamy podobnego tekstu
<audio
src="http://www.yourcompany.com/appName/audio/thankyou.wav">
Będzie wygodniej napisać:
<audio expr="say(thankyou)">
oraz zdefiniować funkcję:
function say(filename) {
return("http://www.yourcompany.com/appName/audio/"
+ filename + ".wav")
}
W JavaScript operator „+” może być zastosowany do łączenia i konkatenacji dwóch łańcuchów
filename jest nazwą pliku, w którym przechowywane jest nagranie odpowiedniego tekstu
Uwaga: aby zastosować funkcję JavaScript tag <audio> musi zastosować atrybut expr, a nie src - to jednak uniemożliwia „cachowanie”
Jeszcze o zmiennych
Zmienne mogą być tworzone lub deklarowane dwoma sposobami:
deklaracja bezpośrednia za pomocą tagu <var>
przy deklaracji pola w formularzu, tworzona jest zmienna o nazwie określonej w tagu <field>
Uwaga: w dokumencie, tag deklarujący zmienną musi być umieszczony przed wyrażeniem, które używa zmiennej.
Można zadeklarować zmienną i jednocześnie przypisać jej wartość, np.:
<var name="squarerootoftwo" expr="Math.sqrt(2)">
Zasięg zmiennej
Jest to zasięg terytorium, w którym zmienna jest dostępna - oznacza to, że te same nazwy (a, b, abc) mogą być zastosowane dla różnych celów w różnych częściach aplikacji;
Ale również może skutkować błędem podczas próby wykorzystania zmiennej poza jej zasięgiem.
Są zmienne predefiniowane dla dowolnego dokumentu VXML i dostępne gdziekolwiek podczas wykonywania na serwerze (na przykład zmienne sesji)
Zmienne deklarowane:
wewnątrz <block>, <filled>, <catch> lub elementu zarządzania zdarzeniami (np. <noinput>) są lokalne dla tego elementu, nie mogą być użyte w wyrażeniach na zewnątrz tego elementu - to jest zasięg anonimowy;
w dialogu form i menu (lecz na zewnątrz <block>, <filled> lub elementu zarządzania zdarzeniami), są lokalne dla tego dialogu - mogą być użyte w wyrażeniach gdziekolwiek w tym dialogu, ale nie gdziekolwiek w dokumencie poza tym dialogiem - zasięg dialogu;
w dokumencie, lecz na zewnątrz dowolnego dialogu, są lokalne dla całego dokumentu; mogą być użyte w wyrażeniach gdziekolwiek w dokumencie - zasięg dokumentu;
w dokumencie root aplikacji za pomocą elementu <var>; te zmienne są dostępne we wszystkich dokumentach tej aplikacji - zasięg aplikacji;
zmienne sesji są tworzone już podczas wybierania numeru do serwisu przez użytkownika; są ustanawiane przez interpreter VXML i tylko do odczytu; są zachowywane przez całą rozmowę, nawet, gdy zmieni się dokument root aplikacji - zasięg sesji.
Zasięg zmiennych tworzy strukturę zagnieżdżoną:
Zgodnie z powyższymi regułami, można używać dwóch zmiennych, które mają tę samą nazwę
Jeżeli ich zasięg nie przekrywa się, interpreter VXML właściwie przypisze zmienną do wyrażenia.
Jeżeli wyrażenie używa nazwy w miejscu gdzie zasięg dwóch zmiennych się przekrywa, interpreter użyje zmiennej bardziej lokalnej, tzn. tej z mniejszym zasięgiem.
Przykład:
Założymy, że jest zmienna aplikacji abc oraz zmienna lokalna abc w określonym dokumencie.
Jeżeli zapiszemy abc w wyrażeniu wewnątrz dokumentu, interpreter użyje zmiennej dokumentu, a nie zmiennej aplikacji.
Jeżeli chcemy to zmienić, można wyraźnie odnieść się do zmiennej aplikacji poprzez zapis application.abc;
Podobnie można zastosować prefiks session., document. i dialog. aby określić odpowiedni zasięg.
Nie ma prefiksu dla zasięgu anonimowego - jest on najbardziej lokalny i nie ma potrzeby wyraźnie tego deklarować.
Standardowe zmienne aplikacji:
application.lastresult$ - zmienna tylko do odczytu, przechowuje wartość ostatniego rozpoznania z zakresu aplikacji
application.lastresult$[i].confidence - przechowuje wartość poziomu zaufania dla danej interpretacji. Zwykle jej wartości jest z zakresu od 0,0 (minimalny poziom zaufania) do 1,0 (maksymalny poziom zaufania). Wartości mogą się różnić na różnych platformach.
application.lastresult$[i].utterance - przechowuje surowy ciąg słów rozpoznanych dla danej interpretacji. Pisownia i proces podziału łańcucha mogą się różnić na różnych platformach.
application.lastresult$[i].inputmode - zawiera informacje dotyczące trybu wprowadzania danego rozpoznania. Możliwe wartości: DTMF lub głosowy.
application.lastresult$[i].interpretation - przechowuje informacje o interpretacji.
Zmienne sesji - dostępność zależy od platformy głosowej i od informacji dostarczanych przez sieć:
session.telephone.ani - dostarcza numer dzwoniącego telefonu, gdy usługa identyfikowania abonenta jest dostępna.
session.telephone.dnis - dostarcza numer wybierany przez użytkownika. Ta informacja jest dostępna tylko wtedy, gdy usługa identyfikacji wybieranego numeru jest świadczona.
session.telephone.iidigits - zawiera informację dotyczącą połączenia - czy zostało wybrane z automatu, czy z telefonu komórkowego. Ta informacja jest dostępna, gdy usługa jest świadczona.
session.telephone.uui - dodatkowa informacja na temat konfiguracji połączeń ISDN świadczonych przez stronę dzwoniącą, gdy usługa jest świadczona.
session.telephone.rdnis - określa numer, z którego połączenie zostało przekierowane do bieżącej lokalizacji lub z którego przeniesienie rozmowy nastąpiło. Na przykład, jeśli użytkownik A dzwoni do użytkownika B i system telefoniczny B przekazuje rozmowę do innego serwera głosowego, wtedy ten serwer głosowy uzyskuje dostęp do informacji dostępnych w zmiennej session.telephone.rdnis, która byłaby numerem systemu użytkownika B ; session.telephone.dnis jest numerem serwera głosowego, a numer użytkownika A jest przechowywany w zmiennej session.telephone.ani.
session.telephone.redirect_reason - zawiera łańcuch, który informuje o przyczynie przekierowania połączenia z oryginalnej lokalizacji do tego serwera. Zmienna ta jest dostępna, gdy session.telephone.rdnis jest wywoływana. Niektóre z możliwych wstępnie przypisanych przyczyn przekierowania: połączenie nieznane, użytkownik zajęty, niedostępny, pora dnia, nie przeszkadzać, daleko, bezwarunkowe, odkształcenia, nie ma odpowiedzi i awaria.Properties
Zmienne VXML properties są predefiniowane i sterują różne właściwości interpretera (wpływają na zachowanie aplikacji). Ustawia się je za pomocą tagu <property>.
Przykład
<property name="timeout" value="5s">
Ustawia wartość timeout na 5 sekund - ta właściwość określa jak długo interpreter będzie czekał na wejście użytkownika zanim zarządzanie zdarzeniami wykona <noinput>
Zakresem tagu <property> jest element, który go zawiera
Przykład:
Załóżmy, że użyje się w/w tagu, aby ustalić timeout 5 sek dla całego dokumentu. Jednocześnie można zapisać następny taki tag wewnątrz formularza lub nawet wewnątrz pojedynczego pola, aby zdefiniować inną wartość timeout dla określonego elementu
Aplikacje i dokumenty root
Gdy cała aplikacja jest zbyt duża, wygodnie byłoby ją podzielić na kilka oddzielnych dokumentów
Normalnie, gdy jeden dokument przekazuje sterowanie do innego, wszystkie zmienne są niszczone i nowy dokument zaczyna od początku
Jednakże często pewne zmienne są potrzebne i można je zachować przy przejściu między dokumentami
Idea aplikacji - zbioru współpracujących dokumentów
Utworzenie takiego zbioru dokumentów wymaga następujących kroków:
utwórz dokument root aplikacji (tag <vxml> nie posiada atrybutu application) , gdzie określone zostaną zmienne i informacje aplikacji, które będą wspólne dla wszystkich dokumentów aplikacji;
we wszystkich pozostałych dokumentach aplikacji wskaż (specyfikuj) dokument root poprzez przypisanie jego nazwy (URI) atrybutowi application tagu <vxml>.
Wykonywanie wielo-dokumentowej aplikacji:
- gdy aktualnie jest interpretowany dokument root
- a wywoływany i ładowany jest inny dokument root : stary dokument jest usuwany, nowy zaczyna być interpretowany;
- a wywoływany i ładowany jest zwykły dokument tej aplikacji (z atrybutem application w tagu <vxml>): obydwa dokumenty pozostają załadowane, interpretowany jest zwykły dokument;
- a wywoływany i ładowany jest zwykły dokument z innej aplikacji:?
- gdy aktualnie jest interpretowany zwykły dokument
- a wywoływany i ładowany jest inny zwykły dokument tej aplikacji: stary dokument jest usuwany, załadowany pozostaje dokument root (w pamięci są dwa dokumenty), interpretowany jest zwykły dokument;
- a wywoływany i ładowany jest zwykły dokument z innej aplikacji:?
Gdy dokument root nie był jeszcze załadowany, a załadowany i interpretowany jest zwykły dokument (z atrybutem application w tagu <vxml>) - interpreter VXML ładuje dokument root wskazany atrybutem application
Gdy root jest załadowany, pozostaje on aktywny dopóki:
albo zakończy się sesja (użytkownik odłoży słuchawkę)
albo inny dokument root zostanie załadowany
Maksymalnie dwa dokumenty aplikacji mogą być załadowane w pamięci interpretera (root i zwykły z tej samej aplikacji), z których tylko jeden będzie w danej chwili przetwarzany przez interpreter
Gdy jeden dokument przekazuje sterowanie do innego, który jest częścią tej samej aplikacji, wszystkie (i tylko) zmienne deklarowane w dokumencie root są zachowywane. To zapewnia wygodny sposób udostępniania informacji dla różnych dokumentów.
Aplikacja może również zdefiniować wspólne gramatyki
Na przykład tag <link> w dokumencie root może zdefiniować gramatykę (np.: prośbę o pomoc lub inną funkcję), która jest następnie aktywna we wszystkich dokumentach aplikacji
Również funkcje JavaScript, które są zdefiniowane w dokumencie root są dostępne dla wszystkich innych dokumentów w aplikacji