CCXML 1.0-W3C Development GuideHome  |  Frameset Home

  tutorial Multi-party Conferencing in CCXML 1.0  |  TOC  |  A: All Things Audio  

Tutorial: Using JSON, <send>, and <foreach>

This lesson will step you through the finer points of utilizing the <foreach> element to manipulate user-Objects, and the Connection Object using the JavaScript Object Notation extensions to the Voxeo platform...take it from us, JSON is really, really cool to work with, and easy, too! In addition, this tutorial will illustrate how a developer can use the <send> tag to asynchonously send an event to a webserver, and receive data back from the request: This last has been a rather common "how do I do this?" question amongst our developer community, and when you ask, we listen, baby! Be fully advised that this tutorial is not at all meant to be attempted by developers who are unfamiliar with the basic concepts outlined in our previous tutorials: If you have not gone through these preceding lessons on CCXML 1.0, then chances are that a lot of the concepts that we cover in this tutorial will be foreign to you, and will likely result in no small amount of confusion.


In this lesson, we will:

Note: The code presented within this tutorial is intended for the "Prophecy - CCXML 1.0" application type only. Attempts to utilize this code on the "CCXML - Voxeo" application type will not function, as the latter platform is based on the W3C specification from 2002.  Prophecy CCXML 1.0 is compliant to the most recent specification from 2006.

Also be aware that you will require a webhost that supports PHP code in order to get the most out of this lesson. While our free webhosting does NOT offer PHP support, you can always download the Prophecy platform and run it locally, which does have PHP support out of the box. Yes, we do think of everything.

Step 1: setting up our Object properties

Right, then. We all know by now how we construct our starting CCXML 1.0 document: an XML declaration here, a CCXML decelaration there, and an <eventprocessor> to enclose all of our <transition> elements. We won't bore you with the simple stuff this time, as you should be familiar with this by now. Instead, let's start out by looking at the <script> that is going to declare our user Object that we will be using later:


<?xml version="1.0" encoding="UTF-8"?>
<ccxml version="1.0" xmlns:voxeo="http://community.voxeo.com/xmlns/ccxml">

<script>
<![CDATA[
//create and object that has a string, an array, and an object>

var myObject = new Object();

//manually assign property values to our user Object
myObject.v1 = 'value_1';
myObject.v2 = 'value_2';

//declare an empty user Array
myObject.Arr = new Array();

//assign values to the [0] and [1] positions of the Array
myObject.Arr.push('array_value_1');
myObject.Arr.push('array_value_2');

//assign a sub-object value to our existing object
myObject.Obj = new Object();
myObject.Obj.Prop = 5;
]]>
</script>

  <eventprocessor>
  </eventprocessor>
</ccxml>


In the above code, we have a few inline notations within our ECMAScript that describe in brief what we are creating and invoking. This is not really the proper forum to discuss JavaScript in a robust, in-depth manner, but a few things might help new users to wrap their heads around what we are doing here. Firstly, JavaScript executes on the client-side, and provides us with a really useful way to work with data in a purely static environment: we can add, multiply, concatenate various bits and pieces of data and shove this data into almost any kind of data type that we want to work with..and in this case, we want to work with Objects. An Object is defined as a collection of either primitive values, (such as numbers, or strings), or composite values, (such as other objects), that can either represent:



Because we have faith in our developers ability to assimilate complex ideas, we will work with both in this tutorial. Cool, huh? We declare this collection of data via the <script> element, and do so at the very top of our CCXML 1.0 document so that our Object values will be scoped document-wide: If we declared them within any given <transition>, then the next <transition> that executes would not be able to access these values that we have so carefully set. Note that any declared variable, Object, or Array that we create within the <script> tag will be accessible directly within the CCXML 1.0 context. To illustrate, both of these variable declarations are essentially identical:


<script>
var myVar ='foo';
</script>

<var name="myVar" expr="'foo'"/>


So, now that we have our user Object all setup, we can start checking out how we can access it's values. 


Step 2: looking at bright, shiny Objects


Our next step is to add some of those <transition> elements that we have become accustomed to, and throw in some <log> statements that are going to output some "raw" values for us. Nothing that you see here should be too shocking and new to you, but just you wait, we get all kinds of fancy later on.


<?xml version="1.0" encoding="UTF-8"?>
<ccxml version="1.0" xmlns:voxeo="http://community.voxeo.com/xmlns/ccxml">

<script>
<![CDATA[
var myObject = new Object();
myObject.v1 = 'value_1';
myObject.v2 = 'value_2';

myObject.Arr = new Array();
myObject.Arr.push('hello');
myObject.Arr.push('world');

myObject.Obj = new Object();
myObject.Obj.Prop = 5;
]]>
</script>

  <eventprocessor>
    <transition event="connection.alerting">
    <accept/>
    <log expr="'***** MYOBJECT = ' + myObject"/>
    </transition>

    <transition event="connection.connected">
      <log expr="'*** Call was accepted ***'"/>
    </transition>

    <transition event="connection.disconnected">
      <log expr="'*** Call was disconnected ***'"/>
      <exit/>
    </transition>

    <transition event="error.*">
      <log expr="'an error has occured (' + event$.reason + ')'"/>
      <log expr="'***  EVENT$.NAME = ' + event$.name"/>
      <log expr="'***  EVENT$.REASON = ' + event$.reason"/>
      <log expr="'***  EVENT$.TAGNAME = ' + event$.tagname"/>
      <log expr="'***  EVENT$.EVENTID = ' + event$.eventid"/>
      <log expr="'***  EVENT$.EVENTSOURCE = ' + event$.eventsource"/>
      <log expr="'***  EVENT$.EVENTSOURCETYPE = ' + event$.eventsourcetype"/>
      <voxeo:sendemail to="'youremail@somewhere.com'"
                      from="'myApp@here.com'"
                      type="'debug'"
                      body="'We had an error! \n Time to panic! \n
                              Flee the cities, abandon all hope!'"/>
    <exit/>
    </transition>

  </eventprocessor>

</ccxml>


As promised, we didn't really do anything surprising in this addition to our code...or did we? The <transition> elements we added for the "connection.alerting", "connection.connected", and our all-purpose error handler for "error.*" are all familiar ground for us here. But if we run the code as-is, our newly-added <log> statement doesn't give us any useful data at all:


log: ***** MYOBJECT = [object Object]


Take note, kids: We can't really output the sub-values of the Object in this manner, as outputting a collection of data via a single reference like this just isn't going to fly: We need to instead get at this information by referencing the property values of our Object. And the easy way to do this is via our <foreach> element. Before we dig too deep into this, let's take a moment and explore an available Object that we don't have to even declare at all: The CCXML 1.0 Connection Object.

The Connection Object is created whenever we <transition> to a "connection.*" event within our CCXML application: More or less, whenever we access a CCXML 1.0 application. The property values of this Object can be really helpful for diagnostic and debugging purposes, and smart coders make a point to <log> this stuff as a matter of course, as it gives us a full-bore breakdown of each relevant telephony event source that is received by the CCXML 1.0 interpreter. These predefined properties we can access pretty easily, as long as we are hip to the right syntax to use:


transitionName.connection.propertyName


In practice, this would look something like:


<transition event="connection.alerting">
<log expr="'***** EVENT$.CONNECTION.CONNECTIONID = ' + event$.connection.connectionid"/>
</transition>


As a further matter of fact, this should be familiar to you already: We have already illustrated the usage of connection Objects within our "CCXML1.0-VoiceXML Dialog" tutorial, (you were paying attention, right?). For the sake of illustration, we won't really access these Object property values via the "traditional" syntax that we use above; oh noes, that would be easy. Instead, we are going to make it even easier, by showing how we can <log> these values, (along with our user Object property values), by leveraging the <foreach> element.


Step 3: using <foreach>


Our next step is to use the <foreach> element to reference our Object, and loop through all the available properties for both our Connection Object, as well as our user-defined Object, so that we can take a gander at our values. What's neat about the <foreach> element is that all we need to do is reference the Object name in the 'object' attribute, and half the battle is won already. Nested cozily within the element itself, we will put our <log> statement that will reference two things:


Pretty simple, no? let's take a peek at what this looks like when added to our code:


<?xml version="1.0" encoding="UTF-8"?>
<ccxml version="1.0" xmlns:voxeo="http://community.voxeo.com/xmlns/ccxml">

<script>
<![CDATA[
var myObject = new Object();
myObject.v1 = 'value_1';
myObject.v2 = 'value_2';

myObject.Arr = new Array();
myObject.Arr.push('hello');
myObject.Arr.push('world');

myObject.Obj = new Object();
myObject.Obj.Prop = 5;
]]>
</script>

  <eventprocessor>
    <transition event="connection.alerting">
    <accept/>
    <log expr="'***** MYOBJECT = ' + myObject"/>

    <foreach object="myObject">
      <log expr="'*** MYOBJECT  ' + index$  + ' PROPERTY VALUE = ' + item$"/>
    </foreach>

    <foreach object="event$.connection">
      <log expr="'*** CONNECTION OBJECT  ' + index$  + ' PROPERTY VALUE = ' + item$"/>
    </foreach>

    </transition>

    <transition event="connection.connected">
      <log expr="'*** Call was accepted ***'"/>
    </transition>

    <transition event="connection.disconnected">
      <log expr="'*** Call was disconnected ***'"/>
      <exit/>
    </transition>

    <transition event="error.*">
      <log expr="'an error has occured (' + event$.reason + ')'"/>
      <log expr="'***  EVENT$.NAME = ' + event$.name"/>
      <log expr="'***  EVENT$.REASON = ' + event$.reason"/>
      <log expr="'***  EVENT$.TAGNAME = ' + event$.tagname"/>
      <log expr="'***  EVENT$.EVENTID = ' + event$.eventid"/>
      <log expr="'***  EVENT$.EVENTSOURCE = ' + event$.eventsource"/>
      <log expr="'***  EVENT$.EVENTSOURCETYPE = ' + event$.eventsourcetype"/>
      <voxeo:sendemail to="'youremail@somewhere.com'"
                      from="'myApp@here.com'"
                      type="'debug'"
                      body="'We had an error! \n Time to panic! \n
                              Flee the cities, abandon all hope!'"/>
    <exit/>
    </transition>

  </eventprocessor>

</ccxml>


Now we have some serious "cool factor" going for our application. When we dial in, we should now see something like this in our application logs:


log: ***** MYOBJECT = [object Object]
log: *** MYOBJECT Arr PROPERTY VALUE = hello,world
log: *** MYOBJECT Obj PROPERTY VALUE = [object Object]
log: *** MYOBJECT v1 PROPERTY VALUE = value_1
log: *** MYOBJECT v2 PROPERTY VALUE = value_2

log: *** CONNECTION OBJECT aai PROPERTY VALUE = 
log: *** CONNECTION OBJECT connectionid PROPERTY VALUE = 9a70627953544110c32262a0db24c434
log: *** CONNECTION OBJECT dialogid PROPERTY VALUE = 
log: *** CONNECTION OBJECT input PROPERTY VALUE = 
log: *** CONNECTION OBJECT local PROPERTY VALUE = 4071112222
log: *** CONNECTION OBJECT originator PROPERTY VALUE = remote
log: *** CONNECTION OBJECT outputs PROPERTY VALUE = 
log: *** CONNECTION OBJECT protocol PROPERTY VALUE = [object Object]
log: *** CONNECTION OBJECT redirect PROPERTY VALUE = 
log: *** CONNECTION OBJECT remote PROPERTY VALUE = 4074181800
log: *** CONNECTION OBJECT state PROPERTY VALUE = 0


Sure, not all these property values are going to be populated, and this is nothing to worry about...kind of hard to have a value for 'dialogid' when we don't have a dialog in our application, of course! But we do have an indication as to what data we can expect, and a solid comparion between a "raw" object, ("myObject" above), versus the object properties that we log via the <foreach> loop. Now we can get even craftier, and see what happens when we try an <send> our user-Object to a webserver....oh I didn't mention that yet? Shame on me. See, we cannot shove a raw Object to a webserver using <send>, so we need to figure out how to get around this. Spend some time on this, and let us know if you have any Bright Ideas; we will wait.

Oh, I have an idea. Why not try out this "JSON.stringify" stuff that we mentioned earlier? That way, we can convert our Object to a String, which subverts this whole limitation with <send>. And while we are at it, we can send back the same String from the webserver back to the CCXML, and then convert it back into an Object using the "JSON.parse" method? Excellent idea, Sherlock. I'll be putting you in for a promotion.


Step 4: the JSON.stringify and JSON.parse methods

Once again, JSON is quite cool, and useful to put into practice for this sort of operation. The two methods that we are concerned with in the scope of this tutorial are the following:


As we declared our Object in the <script> tag right out of the gate at the document scope, we should probably create a stringified version of our Object at the same scope so that we can use it later on when we want to <send> the value. We should also add our <send> tag into the mix so that we can get a feel for how we populate the various attributes to denote the fact that we are sending to an external webserver, and add in our <transition> events for a successful, and an unsuccessful attempt at sending these variables:


<?xml version="1.0" encoding="UTF-8"?>
<ccxml version="1.0" xmlns:voxeo="http://community.voxeo.com/xmlns/ccxml">

<script>
<![CDATA[
var myObject = new Object();
myObject.v1 = 'value_1';
myObject.v2 = 'value_2';

myObject.Arr = new Array();
myObject.Arr.push('hello');
myObject.Arr.push('world');

myObject.Obj = new Object();
myObject.Obj.Prop = 5;
]]>
</script>

  <var name="sendObj" expr="JSON.stringify(myObject)"/>

  <eventprocessor>
    <transition event="connection.alerting">
    <accept/>
    <log expr="'***** MYOBJECT = ' + myObject"/>

    <foreach object="myObject">
      <log expr="'*** MYOBJECT  ' + index$  + ' PROPERTY VALUE = ' + item$"/>
    </foreach>

    <foreach object="event$.connection">
      <log expr="'*** CONNECTION OBJECT  ' + index$  + ' PROPERTY VALUE = ' + item$"/>
    </foreach>
    </transition>

    <transition event="connection.connected">
      <log expr="'*** Call was accepted ***'"/>
      <send name="'http.get'" target="'sendCatcher.php'" targettype="'basichttp'" namelist="sendObj"/>
    </transition>

    <transition event="myEvent">
    <log expr="'***** MYDATA EVENT RECIEVED FROM SERVER *****'"/> 
    </transition>

    <transition event="send.successful">
    <log expr="'***** SEND IS SUCCESSFUL *****'"/>
    </transition>

  <transition event="error.send.targetunavailable">
    <log expr="'***** SEND TARGET UNAVAILABLE *****'"/>
    <exit/>
  </transition>

    <transition event="connection.disconnected">
      <log expr="'*** Call was disconnected ***'"/>
      <exit/>
    </transition>

    <transition event="error.*">
      <log expr="'an error has occured (' + event$.name + ')'"/>
      <log expr="'***  EVENT$.NAME = ' + event$.name"/>
      <log expr="'***  EVENT$.REASON = ' + event$.reason"/>
      <log expr="'***  EVENT$.TAGNAME = ' + event$.tagname"/>
      <log expr="'***  EVENT$.EVENTID = ' + event$.eventid"/>
      <log expr="'***  EVENT$.EVENTSOURCE = ' + event$.eventsource"/>
      <log expr="'***  EVENT$.EVENTSOURCETYPE = ' + event$.eventsourcetype"/>
      <voxeo:sendemail to="'youremail@somewhere.com'"
                      from="'myApp@here.com'"
                      type="'debug'"
                      body="'We had an error! \n Time to panic! \n
                              Flee the cities, abandon all hope!'"/>
    <exit/>
    </transition>
  </eventprocessor>
</ccxml>


Our first new addition to the code is the declaration of the "reObj" variable at the document scope. This variable essentially takes our Object, and converts it into a String prior to us sending the data to the webserver. As indicated, this JSON stuff is really pretty easy to use, and doesn't really require a heck of a lot of explanation.

Most of the handlers and <send> syntax should look familiar, as we dealt with the usage of <send> and it's associated handlers in our CCXML-VXML dialog tutorial. In this case, we will want to specify a 'targettype' value of 'basichttp', (remember, we aren't sending our event to the CCXML session, we are sending to an external webserver). Our handlers themselves for 'send.successful' and 'error.send' are essentially cookie-cutter handlers that we don't do anything really fancy with in this case.

Our new handler for when the webserver sends the value back to us is noteworthy, however: The transition name in this case is going to refelect the event name that is sent back from the PHP; in this case, we are christening it "myEvent". At this point, we will also want to take a peek at the simple PHP that will be accepting the sent data:


sendcatcher.php

<?php

echo "myEvent\n"
?>
<?php
header('Cache-Control: no-cache');


foreach($_REQUEST as $key => $value )
{
    echo $key , "=", $value, "\n";
}

?>



This is our PHP "catcher" script that we will reference in the <send>. Not too much to it at all: It accepts a string value that has been sent to it, and returns the same string back to the invoking application. Feel free to rewrite this using JSP, ASP, .NET, or even ColdFusion, if that suits your coding style; we aren't limited to just PHP for a catcher script.


Step 5: checking our returned value, and reconverting our values back into an Object

Most of the pieces of the puzzle are now in place. We take some Objects, convert them to Strings, then send them to our cool little PHP script that returns the String value to the CCXML 1.0 context. But in a real-world application, we might want to convert a String returned from the webserver into an Object, and maybe loop through the values again, yeah? In this case, we would want to use the JSON.parse method to make this happen. And just to better illustrate what gets converted where, we are going to add a few final <log> statements.


<?xml version="1.0" encoding="UTF-8"?>
<ccxml version="1.0" xmlns:voxeo="http://community.voxeo.com/xmlns/ccxml">

<script>
<![CDATA[
    var myObject = new Object();
    myObject.v1 = 'value_1';
    myObject.v2 = 'value_2';

    myObject.Arr = new Array();
    myObject.Arr.push('hello');
    myObject.Arr.push('world');

    myObject.Obj = new Object();
    myObject.Obj.Prop = 5;
]]>
</script>

  <var name="sendObj" expr="JSON.stringify(myObject)"/>

  <eventprocessor>
    <transition event="connection.alerting">
    <accept/>
    <log expr="'***** MYOBJECT = ' + myObject"/>
 
    <foreach object="myObject">
      <log expr="'*** MYOBJECT  ' + index$  + ' PROPERTY VALUE = ' + item$"/>
    </foreach>

    <foreach object="event$.connection">
      <log expr="'*** CONNECTION OBJECT  ' + index$  + ' PROPERTY VALUE = ' + item$"/>
    </foreach>
    </transition>

    <transition event="connection.connected">
      <log expr="'*** Call was accepted ***'"/>
      <log expr="'***** SENDING DATA ..... NOW! *****'"/>
      <log expr="'***** SENDOBJ = ' + sendObj"/>
      <log expr="'***** MYOBJ = ' + myObject"/>
      <send name="'http.get'" target="'sendCatcher.php'" targettype="'basichttp'" namelist="sendObj"/>
    </transition>


    <transition event="myEvent">
    <var name="reObj" expr="JSON.parse(event$.sendObj)"/>
    <log expr="'***** DATA RECIEVED FROM SERVER *****'"/>

<!-- hey look, its an object -->
      <log expr="'***** AFTER SEND: REOBJ = ' + reObj"/>

<!-- hey look, its now a bunch of strings -->
    <foreach object="reObj">
      <log expr="'*** REOBJ  ' + index$  + ' VALUE = ' + item$"/>
    </foreach>

    <exit/>   
    </transition>

    <transition event="send.successful">
    <log expr="'***** SEND IS SUCCESSFUL *****'"/>
    </transition>

  <transition event="error.send.targetunavailable">
    <log expr="'***** SEND TARGET UNAVAILABLE *****'"/>
    <exit/>
  </transition>

    <transition event="connection.disconnected">
      <log expr="'*** Call was disconnected ***'"/>
      <exit/>
    </transition>
 
    <transition event="error.*">
      <log expr="'an error has occured (' + event$.reason + ')'"/>
      <log expr="'***  EVENT$.NAME = ' + event$.name"/>
      <log expr="'***  EVENT$.REASON = ' + event$.reason"/>
      <log expr="'***  EVENT$.TAGNAME = ' + event$.tagname"/>
      <log expr="'***  EVENT$.EVENTID = ' + event$.eventid"/>
      <log expr="'***  EVENT$.EVENTSOURCE = ' + event$.eventsource"/>
      <log expr="'***  EVENT$.EVENTSOURCETYPE = ' + event$.eventsourcetype"/>
      <voxeo:sendemail to="'youremail@somewhere.com'"
                        from="'myApp@here.com'"
                        type="'debug'"
                        body="'We had an error! \n Time to panic! \n
                            Flee the cities, abandon all hope!'"/>
    <exit/>
    </transition>

  </eventprocessor>

</ccxml>


As indicated, we reconvert our String back into an Object with the "JSON.parse(event$.sendObj)" variable assignation that is highlighted above. We then take this Object , and run it through a <foreach> loop once again to prove to God and Country that yes, we really did re-convert our data back into an Object, and that we weren't just, you know, faking it. After adding in a few <exit> tags into the various <transition> elements to make sure that we receive a programmatic disconnect, our application is 100% complete, and ready for that test call.


  Download the CCXML 1.0 source code!


What we covered:




  ANNOTATIONS: EXISTING POSTS
0 posts - click the button below to add a note to this page

login
  tutorial Multi-party Conferencing in CCXML 1.0  |  TOC  |  A: All Things Audio  

© 2008 Voxeo Corporation  |  Voxeo IVR  |  VoiceXML & CCXML IVR Developer Site