| VoiceXML 2.1 Development Guide | Home | Frameset Home |
<foreach> element, which allows the developer an inherent browser method for looping through items in an array, and outputting them via TTS, or via <audio>. This element must specify both the 'array', as well as the 'item' attributes, else an error.semantic will be thrown.
| array | Data Type: (ECMAScript Expression) | Default: Required |
The 'array' attribute defines the name of the array referenced by the <foreach> element,; failure to specify this attribute will result in an error.semantic event being thrown. | ||
| item | Data Type: NMTOKEN | Default: Required |
The 'item' attribute denotes the name of the variable that stores a particular array value as it is being iterated within the loop. If this variable is not already defined, then it will be declared upon invocation of the <foreach> element. | ||
| <?xml version="1.0" encoding="UTF-8"?>
<vxml version = "2.1"> <meta name="author" content="Matthew Henry"/> <meta name="copyright" content="2005 voxeo corporation"/> <meta name="maintainer" content="YOUR_EMAIL@HERE.COM"/> <form id="F1"> <block> <prompt> welcome to the gaming news phone network. </prompt> <script> var arrayGames = ["duke nukem forever", "half life 2", "doom 3", "shadow warrior 2", "track and field: grecian edition" ]; </script> <prompt> The most anticipated games for this year are <break/> </prompt> <foreach item="games" array="arrayGames"> <prompt><value expr="games"/><break/></prompt> </foreach> <prompt> But of course, we all know that Duke Nukem Forever is never, ever, ever, going to be released, so gamers may as well pin their hopes on Miss Pac Man 3, or Command and Conquer: French Assault.</prompt> </block> </form> </vxml> |
| ANNOTATIONS: EXISTING POSTS |
mkoe
|
|
| Hi,
How can I use <subdialog> in a <foreach>? It seems the vxml doesn't allow to execute subdialog within <foreach>. I put my sample as the following. Thanks for your help. <form name="main"> <foreach item = "theCurrentSAVAccout" array = "SAVAccoutList"> <subdialog name="result" src="#SayAccountInformation"> <param name="currentMonth" expr="theCurrentSAVAccout.currentMonth" /> <param name="previousYear" expr="theCurrentSAVAccout.previousYear" /> <param name="isJanToMay" expr="theCurrentSAVAccout.isJanToMay" /> <filled /> </subdialog> </foreach> </form> <form name="theCurrentSAVAccout"> <block> </block> </form> When I run the above code in IBM VoiceToolkit, I am getting error --------------------------------------------------------- INFO: Call is connected. ERROR - Cause: VXML Document error: and form the system error log. [7/4/06 11:20:21:250 EDT] 254cc570 VXML E 3006509539553984@127.0.0.1 TRAS0014I: The following exception was logged com.ibm.voice.server.vc.VContainerException: VContainer::dialogRun at com.ibm.voice.server.vc.core.VContainer.dialogRun(VContainer.java:389) at com.ibm.voice.server.vxp.VXPRuntime$RunWorker.runWork(VXPRuntime.java:747) at com.ibm.voice.server.vxp.VXPWorker.run(VXPWorker.java:84) at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:912) Caused by: com.ibm.vxi.intp.BrowserProcException: VXIContext::interpret: at com.ibm.vxi.intp.VXIContext.interpret(VXIContext.java:512) at com.ibm.vxi.intp.VoiceBrowser.run(VoiceBrowser.java:570) at com.ibm.voice.server.vc.core.VContainer.dialogRun(VContainer.java:383) ... 3 more Caused by: error.badfetch:com.ibm.vxi.intp.CatchEvent: file:/C:/myViews/snapshots/MKOE_VoiceXML/vxml/ITSWebProject/WebContent/main/vxml/interestEarned.vxml:VXML Document error: Line : 353 Column: 18 URI : null <SNIP> |
|
MattHenry
|
|
|
Hello there, I think that there is a bit of confusion that I should clear up. Checking the parent-child listing for theelements in question, <subdialog> is not a valid child of <foreach>, so this is not a valid option. You could however, code a foreach loop on the serverside, and output your subdialogs as needed. ~Matt |
|
dragondad
|
|
| Can I use the <foreach> recursively to support two dimensional array assignment.
For example: <foreach item="games" array="arrayGames"> <prompt><value expr="games"/><break/></prompt> <foreach item="scores" array="arrayScores"> <prompt><value expr="scores"/><break/></prompt> </foreach> </foreach> this looks like a valid script, but will the result as expected. |
|
MattHenry
|
|
|
Hi there, I haven't tested this personally, but I see no reason why this wouldn't work. If you want to give me a sample array that is specific to this topic, I can run a test and find out, though...let me know. ~Matt |
|
shawnaslam1
|
|
| My question is once we have assigned the array string to the VXML array now can we access the specific index of the VXML array as we can do in any language or in JSP.
It seems to me that when we use array in foreach loop it plays the array and didn't give us any control so is there any way in we each we can access the specific index of the array. your spontaneous action will be great for me. Regards, Shawn Aslam |
|
MattHenry
|
|
|
Hi Shawn, What you are looking to do in this case exceeds what the <foreach> element was designed to do. If you want finer-grained control over accessing individual index positions and their associated values, then you would likely be better off doing this by crafting an ECMAScript function to achieve this goal. Hope this helps, ~Matthew Henry |
|
Vijeth
|
|
| Hello Matt,
I am trying to what is the value of each element of an array. But i'm not getting how to?? Following is my code <vxml xmlns="http://www.w3.org/2001/vxml" xml:lang="en-IN" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.w3.org/2001/vxml http://www.w3.org/TR/voicexml20/vxml.xsd" version="2.0"> <form id="recharge"> <script> <![CDATA[ function say(number){ var dig= new Array(); for(var i=0; i<number.length; i++) dig[i]=number.charAt(i); return dig; } ]]> </script> <field name="select" type="digits" > <prompt> please enter the recharge code followed by # </prompt> <nomatch> <prompt> nomatch </prompt> <reprompt/> </nomatch> <noinput> <prompt> call you later</prompt><reprompt/> </noinput> <filled> <var name="x" expr="say(select)"/> <foreach array="x" item="xx"> <if cond="x==1"> <prompt>one</prompt> <else/> <prompt>other</prompt> </if> </foreach> </filled> </field> </form> </vxml> I want "one" prompt should be played when i'd pressed 1#. Please help me out. |
|
voxeoJeffK
|
|
| Hi,
Your <foreach> code looks fine for the most part. I would recommend single quoting the conditionals so that they are tested as a string like so: <if cond="x=='1'">. I added a few more iterations to test your code, and it seems to work just fine: <filled> <var name="x" expr="say(select)"/> <foreach array="x" item="xx"> <if cond="x=='1'"> <prompt>you chose one</prompt> <elseif cond="x=='2'"/> <prompt>you chose two</prompt> <elseif cond="x=='3'"/> <prompt>you chose three</prompt> <else/> <prompt>you chose other</prompt> </if> </foreach> </filled> Regards, Jeff K. |
|
Vijeth
|
|
| Thank you Jeff, It worked. | |
mtatum111
|
|
| I am a little confused here. Just not sure when to use CDATA and not to use CDATA
We have <script> var arrayGames = ["duke nukem forever", "half life 2", "doom 3", "shadow warrior 2", "track and field: grecian edition" ]; </script> why wouldn't we have the following instead <script> <![CDATA[ var arrayGames = ["duke nukem forever", "half life 2", "doom 3", "shadow warrior 2", "track and field: grecian edition" ]; ]]> </script> |
|
VoxeoDustin
|
|
| Hey Melissa,
CDATA is only necessary to escape characters normally reserved in XML, such as <, >, &. In the code you pasted, it is not necessary as there are no reserved characters in use that might cause an XML parse error. Thanks, Dustin |
|
mszlazak
|
|
| Here is MyScript.js file
function myArray() { return ['05:30 PM','05:35 PM','05:40 PM','05:45 PM','05:50 PM','05:55 PM','06:00 PM']; } which just returns an array of stings the last being '06:00 PM'. Here is my vxml file is as follows but if I say "yes" to any time, for instance when I'm prompted '05:35 PM', I always get back "you said yes to 06:00 PM." I'm not seeing why, <assign name="opening" expr="i"/>We have an opening at <value expr="opening"/>, works but, <if cond="MyResp == 'yes'"><prompt>You said yes to <value expr="opening"/>.</prompt>, does work. <?xml version="1.0" encoding="UTF-8"?> <vxml version="2.1"> <script src="MyScript.js" maxage="5000" maxstale="5000"/> <form id="f1"> <var name="opening" expr=""/> <field name="MyResp"> <grammar type="text/gsl"> <![CDATA[[yes]]]> </grammar> <prompt> When you hear the time you want please say yes<break/> <foreach item="i" array="myArray()"> <assign name="opening" expr="i"/> We have an opening at <value expr="opening"/><break/>Is that good for you?<break/> </foreach> </prompt> <noinput> I did not hear anything. Please try again. <reprompt/> </noinput> <nomatch> I did not recognize that. Please try again. <reprompt/> </nomatch> </field> <filled namelist="MyResp"> <if cond="MyResp == 'yes'"> <prompt>You said yes to <value expr="opening"/>.</prompt> <else/> <prompt> A match has occurred, but no specific if statement was written for it. </prompt> </if> </filled> </form> </vxml> |
|
voxeoJeffK
|
|
| Hello,
The input variable being filled does not automatically "break" the loop. The foreach will run its course as the prompt queue is emptied, and as you can see the final array element is what has been assigned to "opening". I think what you are trying to do here would be better suited for the <mark> element, and we have a full tutorial on its use here: http://www.vxml.org/t_21.6.htm Regards, Jeff Kustermann Voxeo Support |
|
mszlazak
|
|
| Hi Jeff.
Yes. I was looking at the <mark> element before but using it seems to require a bunch of conditionals for each possible "time" and to cover all possibilities (used or not) I would have to allow for the minimum possible time interval (5 minutes) on a 24 hour day. In other words, 1440 if-then statements. What I would like is the "time" or index to my array that is associated with the barge-in "Yes" stored in a place where I can repeat it back like <if cond="MyResp == 'yes'"> <prompt>You said yes to <value expr="opening"/>.</prompt> How do I do that? Also, I've tried using <mark> as follows but it gives me an "internal error" in the foreach statement. <?xml version="1.0" encoding="UTF-8"?> <vxml version="2.1"> <script src="MyScript.js"/> <form id="pick_opening"> <var name="opening" expr=""/> <var name="opening_idx" expr="0"/> <field name="myResp"> <grammar type="text/gsl"><![CDATA[[yes]]]></grammar> <prompt> When you hear the time you want please say yes<break/> <foreach item="i" array="myArray()"> <assign name="opening" expr="i"/> We have an opening at <value expr="opening"/><break/>Is that good for you?<break/> <mark nameexpr="opening_idx++"/> </foreach> </prompt> <noinput> I did not hear anything. Please try again. <reprompt/> </noinput> <nomatch> I did not recognize that. Please try again. <reprompt/> </nomatch> </field> <filled namelist="myResp"> <if cond="myResp == 'yes'"> <prompt>You said yes to <value expr="opening"/>.</prompt> <else/> <prompt> A match has occurred, but no specific if statement was written for it. </prompt> </if> </filled> </form> </vxml> |
|
VoxeoDustin
|
|
| Hey Mark,
Since there are not any input items that are valid children of foreach, we can use a little trickery to 'loop' an input item. Here, I used a field with the built-in type boolean(yes, yeah, true, no, nope, false, etc). I create an array and a counter variable and simply catch the noinput event, increment the variable and reprompt the caller with the next slot of the array: <?xml version="1.0" encoding="UTF-8" ?> <vxml version="2.1"> <var name="counter" expr="0"/> <var name="selection"/> <script> var arrayGames = ["duke nukem forever", "half life 2", "doom 3", "shadow warrior 2", "track and field: grecian edition" ]; </script> <form> <block> <prompt> Please say Yes when you hear the item you would like to purchase </prompt> </block> <field type="boolean"> <property name="timeout" value="1500ms"/> <prompt> <value expr="arrayGames[counter]"/> </prompt> <noinput> <assign name="counter" expr="counter+1"/> <reprompt/> </noinput> <filled> <prompt> You selected <value expr="arrayGames[counter]"/>. </prompt> </filled> </field> </form> </vxml> This is a very simple example, but should get you on right track. Let me know if we can be of further assistance. Cheers, Dustin Hayre Customer Support Engineer 2 Voxeo Support |
|
mszlazak
|
|
| Hi Dustin.
That worked. Thanks Also, could you point me to information on how to get the array of "times", which I've hard coded into the above vxml script, if instead I'm reading those "times" via php from a data base. Mark. |
|
VoxeoDustin
|
|
| Hey Mark,
Here is a quick bit of PHP to get you started. Since our support for server-side scripting here is limited, I'll leave the DB queries up to you. ;) <?php $get_times = array('5:30','6:00','6:30','7:00','7:30','8:00'); header('Cache-Control: no-cache'); print('<?xml version="1.0" encoding="UTF-8" ?>'); ?> <vxml version="2.1"> <var name="counter" expr="0"/> <var name="selection"/> <script> var arrayTimes = [<?php $i = 0; while($i < sizeof($get_times) - 1) { echo "\"" . $get_times[$i], "\","; $i++; } echo "\"" . $get_times[$i], "\""; ?> ] </script> <form> <block> <prompt> Please say yes when you hear the time you would like to schedule your appointment. </prompt> </block> <field type="boolean"> <property name="timeout" value="1500ms"/> <prompt> <say-as interpret-as="time"> <value expr="arrayTimes[counter]"/> </say-as> </prompt> <noinput> <if cond="counter < arrayTimes.length-1"> <assign name="counter" expr="counter+1"/> <reprompt/> <else/> <prompt> You did not select a time. Please say yes when you hear the time you wish to schedule. </prompt> <assign name="counter" expr="0"/> <reprompt/> </if> </noinput> <filled> <prompt> You selected <say-as interpret-as="vxml:time"> <value expr="arrayTimes[counter]"/> </say-as> </prompt> </filled> </field> </form> </vxml> Also note that I corrected a logistical error in my first draft that caused the prompt to continue outside of the bounds of the array, resulting in 'undefined' prompts. Cheers, Dustin Hayre Customer Support Engineer 2 Voxeo Support |
|
aakoum
|
|
| I am trying to excute If inside Foreach outside of filled element but iit play the index but never execute the if satement. could you please tell me what is wrong:
<?xml version="1.0" encoding="UTF-8" ?> <vxml version="2.1" xmlns="http://www.w3.org/2001/vxml"> <form> <script> var arrayGames = ["pizza", "drinks", "salad", "wings"]; </script> <field name="orderItem"> <grammar> pizza | drinks | salad | wings </grammar> <prompt> <foreach item="games" array="arrayGames"> <prompt><value expr="games"/><break/></prompt> <if cond="games=='pizza'"> <prompt> You choose one</pormpt> <elseif cond="games=='drinks'"/> <prompt> You choose two</pormpt> <elseif cond="games=='salad'"/> <prompt> You choose three</pormpt> <else/> <prompt> You choose four</pormpt> </if> </foreach> </prompt> <noinput> Say pizza, drinks, salad or wings. </noinput> <nomatch> <prompt>You can say pizza, drinks, salad or wings</prompt> <reprompt/> </nomatch> <help> <reprompt/> </help> </field> <filled mode="any"> <prompt> you must have filled but one field </prompt> <clear namelist="orderItem"/> <reprompt/> </filled> </form> </vxml> |
|
voxeo_chris
|
|
| Hello,
I went through your code and noticed a few problems that might be causing you the inability to run your application on our platform. The first problem I noticed was the fact that you were misspelling your </prompt> statments in a few places which was causing a parsing error. You also were including an octet-stream grammar which is unsupported on the Voxeo platform. After correcting these problems, the entire application was working as intended including the <if> statement. I have included my code that I used for your own review highlighting my changes. Please let us know if you have any other questions. [code] <?xml version="1.0" encoding="UTF-8" ?> <vxml version="2.1" xmlns="http://www.w3.org/2001/vxml"> <form> <script> var arrayGames = ["pizza", "drinks", "salad", "wings"]; </script> <field name="orderItem"> [b] <grammar xmlns="http://www.w3.org/2001/06/grammar" xml:lang="en-US" root = "MYRULE"> <rule id="MYRULE"> <one-of> <item> pizza </item> <item> drinks </item> <item> salad </item> <item> wings </item> </one-of> </rule> </grammar> [/b] <prompt> <foreach item="games" array="arrayGames"> <prompt> <value expr="games"/> <break/> </prompt> <if cond="games=='pizza'"> <prompt> You choose one[b]</prompt>[/b] <elseif cond="games=='drinks'"/> <prompt> You choose two[b]</prompt>[/b] <elseif cond="games=='salad'"/> <prompt> You choose three[b]</prompt>[/b] <else/> <prompt> You choose four</prompt> </if> </foreach> </prompt> <noinput> Say pizza, drinks, salad or wings. </noinput> <nomatch> <prompt>You can say pizza, drinks, salad or wings[b]</prompt>[/b] <reprompt/> </nomatch> <help> <reprompt/> </help> </field> <filled mode="any"> <prompt> you must have filled but one field [b]</prompt>[/b] <clear namelist="orderItem"/> <reprompt/> </filled> </form> </vxml> [/code] Regards, Chris Bruckart Customer Engineer Voxeo Support |
|
aakoum
|
|
| Thanks chris for your info. I just want to confirm with you :
Did you hear Pizza and then you choose one , Drinks you choose two. For me it always play pizza drinks slad wings . That's it What does [b] do in your case? Thanks in advance |
|
voxeo_chris
|
|
| Hello again,
The [b] is simply some markup we include in the ticketing system to emphasis certain things. The code provided below is cleaned up just so we can keep everything simple. Just to be clear, it does indeed output "You choose one pizza, you choose two drinks... etc". I retested to be 100% sure so all you would need to do is copy and paste the code into a VXML application in your account and it should work flawlessly. If you are still having problems, just let us know and we would be glad to look further into it. <?xml version="1.0" encoding="UTF-8" ?> <vxml version="2.1" xmlns="http://www.w3.org/2001/vxml"> <form> <script> var arrayGames = ["pizza", "drinks", "salad", "wings"]; </script> <field name="orderItem"> <grammar xmlns="http://www.w3.org/2001/06/grammar" xml:lang="en-US" root = "MYRULE"> <rule id="MYRULE"> <one-of> <item> pizza </item> <item> drinks </item> <item> salad </item> <item> wings </item> </one-of> </rule> </grammar> <prompt> <foreach item="games" array="arrayGames"> <prompt> <value expr="games"/> <break/> </prompt> <if cond="games=='pizza'"> <prompt> You choose one</prompt> <elseif cond="games=='drinks'"/> <prompt> You choose two</prompt> <elseif cond="games=='salad'"/> <prompt> You choose three</prompt> <else/> <prompt> You choose four</prompt> </if> </foreach> </prompt> <noinput> Say pizza, drinks, salad or wings. </noinput> <nomatch> <prompt>You can say pizza, drinks, salad or wings</prompt> <reprompt/> </nomatch> <help> <reprompt/> </help> </field> <filled mode="any"> <prompt> you must have filled but one field </prompt> <clear namelist="orderItem"/> <reprompt/> </filled> </form> </vxml> Regards, Chris Bruckart Customer Engineer Voxeo Support |
|
beruhy
|
|
| I'm supposing a <goto> inside a foreach breaks the loop. Am I right?
If so, is there a sure way to loop over the execution of a separate form? Something like this: <foreach array="arr" item="it"> <goto next="#hello"/> </foreach> This would call the hello form a certain number of times. Thanks |
|
VoxeoDustin
|
|
| Hey,
I think the best way to achieve what you want is to leverage the form interpretation algorithm of VoiceXML and force a field to be revisited a certain number of times: <?xml version="1.0"?> <vxml version="2.1"> <script> var arrayGames = ["duke nukem forever", "half life 2", "doom 3", "shadow warrior 2", "track and field: grecian edition" ]; </script> <var name="counter" expr="0"/> <form> <block name="playback" cond="counter < arrayGames.length"> <prompt> <value expr="arrayGames[counter]"/> </prompt> <assign name="counter" expr="Number(counter)+1"/> <clear namelist="playback"/> </block> </form> </vxml> Let me know if this is what you're looking for. Cheers, Dustin Hayre Customer Support Engineer 2 Voxeo Support |
|
pppeter
|
|
| Hi, I was wondering if there is a way to use <foreach> (or some other way) to iterate over a list and provide a dynamic set of <choice> elements inside a menu. Basically, I have something like
<menu id="test" dtmf="true"> <prompt> To go to destination A, say A. To go to destination B, say B. </prompt> <catch> .. some stuff .. </catch> <choice next="destination_a"> a </choice> <choice next="destination_b"> b </choice> </menu> And I want to have this <menu> element dynamically iterate through a list, both in the prompts and in the <choice>'s. I can see how to easily use <foreach> to iterate through the prompts I need, but I'm not sure how to iterate through the <choice> elements. Perhaps I need to do something other than use <choice> stuff, but I'm not sure what to do. Is there any way to replicate the behavior of <choice>'s over a dynamic list using <foreach> ? Thanks, Peter |
|
MattHenry
|
|
|
Hello Peter, I suspect that this attempt to use the <foreach> element might be outside of what you can really do in a static-only context, as foreach is not a valid parent of <choice>, <grammar>, etc. However, this is *exactly* what using a foreach loop in the dynamic context is used for when writing IVR application content, as you can define the array within the dynamic context, then output whatever XML you want via dyanmic means. I'm not sure what dynamic markup you really prefer, but to give you some idea of how you might do this, you can check [url=http://www.tizag.com/phpT/foreach.php]this link[/url] for some pointers to help get you started. Regards, ~Matthew Henry |
|
pppeter
|
|
| Thanks, Matthew, for the quick reply!
I agree, I should be building the VXML on the server side. Do you have a sample application that uses <data> to retrieve VXML from the server side? All the samples I see on the Voxeo site seem to send / receive parameters, but I don't see any that show how to affect the VXML _itself_ using <data>. Can you point me at a sample for that? Thanks again, Peter |
|
voxeoJohn
|
|
| Hello Peter,
Just a suggestion, but if you are looking to transition from one page and dynamically generally a second dialog based on values from the parent dialog you may want to check out the <submit> ( http://docs.voxeo.com/voicexml/2.0/submit.htm ) element which transitions control to a new document, via HTTP request, and includes the ability to post/get values in a space delimited name list. I do hope this helps, and if there are any other questions please don't hesitate to ask as we are most certainly standing by to assist! Regards, John Dyer Customer Engineer Voxeo Support |
|
pppeter
|
|
| Hi John,
I guess I'm wondering if there's a way to do it without transitioning - I am trying to dynamically create a <menu> element, or something that would serve the same purpose. I'm guessing the way I should do this is to do a <goto> that would call a VXML I load up from my server side. Peter |
|
voxeoJohn
|
|
| Hello,
I think you may be discounting the submit to quickly here, as this is the element of choice here. Let me try to explain my reasoning here; Your application flow in this case would be as follows: We have an root document (root.xml) and a main document (main.xml). So it goes like this....main.xml does some fun VUI interaction, and then submits to a leaf document (leaf.xml) which is dynamically generated. So leaf.xml references the root.xml, which allows the leaf document to reference and assign any values to application scoped variables. So now once you are done in your leaf document we simply transition back to the main via the <goto> element. I do hope this helps clear up this confusuiion, and please let us know if there is anything else we can do to assist please let us know! Regards, John Dyer Customer Engineer Voxeo Support |
| login |