Consuming the CMX Web Service with ColdFusion MX

Web Services is a fairly new technology that has become very popular in the past few years. Basically, a Web service is a service that is created to communicate, using standard XML formats, to any application that knows how to talk to it. The Web service will have a public interface written in Web Service Description Language (WSDL). The interface describes what the Web service does and how to communicate with it. The actual communication is done with XML, typically using the SOAP protocol. Because XML is basically just text, an application that can read text can read and interpret a Web service. Because of this, Web services can be created by one type of server and utilized by anyone who can read the XML.

ColdFusion MX has made working with Web services even easier by allowing the developer to interact with Web services by using traditional ColdFusion-style tags. Also, Dreamweaver MX can introspect these services in the Components panel, and it will automatically create the ColdFusion MX code necessary to utilize the services.

Community MX publishes a web service that will display information about the latest content available from the site. This service can be used by anyone who knows how to consume a web service. Content of Community MX is copyright © 2003 by Community MX and cannot be redistributed, however you may use the web service on your own site to supply a list of what is available.

The Community MX web service utilizes a standard .wsdl file that can be consumed by any technology that can consume a web service. The web service is located at http://www.communitymx.com/services/cmxfeed.wsdl. The web service exposes 4 methods:

*not implemented yet

Dreamweaver MX is the tool of choice for building ColdFusion MX pages because of the built-in features for CF MX, such as the Components panel which simplifies the process of building and consuming web services. The Components panel allows you to specify a URL for the .wsdl file, and the web service consumer code is created automatically by Dreamweaver MX. We'll show you how to add the getContent, searchContent, and getContentTypes services to your ColdFusion page.

Using getContent

The getContent method simply returns the latest content to your service without any kind of filtering, or filtering by contentType only. It is essentially a dump of the the latest content descriptions from the site. The next section will show how to consume the service using Dreamweaver MX.

Step by step:

  1. Open Dreamweaver MX to a blank ColdFusion page in your site. You can name the page example1.cfm.
  2. Open the Components panel and choose Web Services in the dropdown box.
  3. Click the plus sign (+) to add a new web service. That brings up the following dialog box:

  1. Type in the location of the Community MX .wsdl file (http://www.communitymx.com/services/cmxfeed.wsdl) and click OK. This will generate a proxy for the web service locally in your temp directory, and create the appropriate menu entries in your Dreamweaver MX configuration folder. The Components menu should be populated with the service information at this point:

  1. The next step is to add the service to the page. The service should be instantiated in Code View. Simply drag the Object[] getContent tree branch to the page. This will supply the following code:

<cfinvoke
 webservice="http://www.communitymx.com/services/cmxfeed.wsdl"
 method="getContent"
 returnvariable="aObjectArray">
<cfinvokeargument name="type" value="enter_value_here"/>
</cfinvoke>

The <cfinvoke> tag invokes the web service from the webservice URL. The method is getContent, and it returns an array of objects. As you can see, there is an optional argument for "type". We will use the default option of 0 to show all types of content:

<cfinvoke
 webservice="http://www.communitymx.com/services/cmxfeed.wsdl"
 method="getContent"
 returnvariable="aObjectArray">
<cfinvokeargument name="type" value="0"/>
</cfinvoke>

  1. The fields in the object are as follows:

    AUTHOR
    CATEGORY
    DESCRIPTION
    KEYWORDS
    TITLE
    TYPE_DESCRIPTION
    URL

    We will display these fields as if we were displaying a query, using a <cfloop> and a table:

<cfloop from="1" to=#ArrayLen(aObjectArray)# index="i">
<table>
  <tr>
    <td>Title</td>
    <td><cfoutput>#aObjectArray[i].Title#</cfoutput></td>
  </tr>
  <tr>
    <td>Keywords</td>
    <td><cfoutput>#aObjectArray[i].Keywords#</cfoutput></td>
  </tr>
  <tr>
    <td>Author</td>
    <td><cfoutput>#aObjectArray[i].Author#</cfoutput></td>
  </tr>
  <tr>
    <td>Category</td>
    <td><cfoutput>#aObjectArray[i].Category#</cfoutput></td>
  </tr>
  <tr>
    <td>Type</td>
    <td><cfoutput>#aObjectArray[i].type_description#</cfoutput></td>
  </tr>
  <tr>
    <td>Description</td>
    <td><cfoutput>#aObjectArray[i].description#</cfoutput></td>
  </tr>
</table>
</cfloop>

  1. Lastly, we'll add the URL field as a link on the Title field, by selecting the text in Design view and using the property inspector to set the link:

After adding a couple of styles to the page, the result looks like this.

The page code can be viewed here (you might have to View Source in your browser).

Using searchContent

The searchContent method returns the latest content to your service using search criteria that you provide. It is a search of the latest content descriptions from the site, just as if you were searching the site itself from a search box on the site. The next section will show how to consume the service method using Dreamweaver MX.

Step by step:

  1. First, follow steps 1 - 4 from the previous section on getContent. The steps are the same. You can name the new page example2.cfm.
  2. Next, drag the Object[] searchContent tag to the page from the Components panel. This will give you the following code:

<cfinvoke
 webservice="http://www.communitymx.com/services/cmxfeed.wsdl"
 method="searchContent"
 returnvariable="aObjectArray">
  <cfinvokeargument name="search" value="enter_value_here"/>
  <cfinvokeargument name="anyWords" value="enter_value_here"/>
  <cfinvokeargument name="exactPhrase" value="enter_value_here"/>
  <cfinvokeargument name="contentType" value="enter_value_here"/>
  <cfinvokeargument name="contentDate" value="enter_value_here"/>
</cfinvoke>

As you can see there are 5 optional arguments: search, anyWords, exactPhrase, contentType, and contentDate.

search: the search word or words. This can be individual words, comma separated words, or phrases
anyWords: true to match any of the search words, rather than the default of "all words"
exactPhrase: true to match an exact phrase
contentType: 0 for all, or match one of the CMX content types, which can be found by using the getContentTypes method of the service
contentDate: search based on a time period, as number of days (defaults to 30)

  1. We'll do this demonstration with just one parameter--search--and fill in default values for the rest. Examples 3 and 4 will show the other arguments.

  <cfinvokeargument name="search" value=#form.search# />
  <cfinvokeargument name="anyWords" value="false" />
  <cfinvokeargument name="exactPhrase" value="false" />
  <cfinvokeargument name="contentType" value="0" />
  <cfinvokeargument name="contentDate" value="30" />

  1. We'll use the same display table that was created for the first example, but for this example we'll add a search field to the page:

<form name="form1" method="post" action="example2.cfm">
  <input name="search" type="text" id="search">
  <input type="submit" name="Submit" value="Search">
</form>

  1. We'll add a <cfparam> statement at the top of the page to give our form element a default value:

<cfparam name="form.search" default="test">

  1. One last item to make the page a little more user friendly -- a message for the user if there are no matches found. We can do that with a little bit of conditional logic:

<cfif form.search NEQ "" AND ArrayLen(aObjectArray) EQ 0>
  <h2>No matches found.</h2>
</cfif>

Browse the page and you should see the result similar to this.

The page code can be viewed here (you might have to View Source in your browser).

Utilizing getContentTypes

To add a content list to the search, utilize the getContentTypes method of the service. These content types are generated dynamically because of the changing nature of the Community -- new content and content types are being added regularly. As of this writing, the getContentTypes method returns this result:

0, ALL
1, Article
2, Tutorial
3, FAQ
4, Review
5, Extension
6, Daily Tips
7, Weekly Tips
1000, Knowledge Base

The method returns an array of objects. Each object contains a type_id and a type_desc. These properties can be fed into a dropdown list. To add the dropdown list to Example 2, follow these steps:

Step by step:

  1. Follow the steps presented for Example 2. That will be the starting point. The new page can be called example3.cfm.
  2. Drag the Object[] getContentTypes method from the Component panel to the page in code view. You can place this below the previous <cfinvoke> tag.
  3. Add a dropdown list (<select> tag) to the form. The select field will be fed by the web service with a loop. The code will look like this:

<select name="contentType">
  <cfloop index="j" from=1 to=#ArrayLen(theArray)#>
  <cfoutput>
  <option value="#theArray[j].type_id#"
    <cfif form.contenttype EQ theArray[j].type_id>selected="selected"     </cfif>>#theArray[j].type_desc#</option>
  </cfoutput>
  </cfloop>
</select>

As you can see, the type_id and type_desc properties feed the list.

  1. Add the dropdown box as a <cfparam> tag to the top of the page along with the form.search field that is already there so that there is always a default value for the dropdown box.

<cfparam name="form.search" default="">
<cfparam name="form.contenttype" default="0">

The completed example can be seen here.

The page code can be viewed here (you might have to View Source in your browser).

Utilizing the searchContent Method with Arguments

Lastly, we'll show you how to fully utilize the searchContent method using all 5 arguments that the method will take. The example will be based on Example 3 and use that as a starting point. The previous example showed the use of the search and contentType arguments. This example will add the anyWords, exactPhrase, and contentDate arguments.

  1. First, follow the steps to create the previous example (Example 3). The new page will be called example4.cfm.
  2. Next, add the new form fields to the page. We'll use two new dropdown boxes (<select> tags) to implement the features. The code for the entire form is as follows, with the two new form elements highlighted:

<form name="form1" method="post" action="">
<table width="445">
  <tr>
    <td><div align="right">Content type: </div></td>
    <td>
      <select name="contentType">
        <cfloop index="j" from=1 to=#ArrayLen(theArray)#>
            <cfoutput>
                <option value="#theArray[j].type_id#" <cfif form.contenttype EQ theArray[j].type_id>selected="selected" </cfif>>#theArray[j].type_desc#</option>
            </cfoutput>
          </cfloop>
        </select></td>
  </tr>
  <tr>
    <td><div align="right">Search type:</div></td>
    <td>
      <select name="searchtype" id="select2">
        <option value="0" <cfif form.searchtype EQ 0>selected="selected" </cfif>>All words</option>
        <option value="any" <cfif form.searchtype EQ "any">selected="selected" </cfif>>Any words</option>
        <option value="exact" <cfif form.searchtype EQ "exact">selected="selected" </cfif>>Exact Phrase</option>
      </select></td>
  </tr>
  <tr>
    <td><div align="right">Date range: </div></td>
    <td>
      <select name="daterange" id="select3">
          <option value="7" <cfif form.daterange EQ 7>selected="selected" </cfif>>Past week
          <option value="30" <cfif form.daterange EQ 30>selected="selected" </cfif>>Past month
          <option value="90" <cfif form.daterange EQ 90>selected="selected" </cfif>>Past 90 days
        </select></td>
  </tr>
  <tr>
    <td><div align="right">Search for: </div></td>
    <td><input name="search" type="text" id="search2" value="<cfoutput>#form.search#</cfoutput>">
    <input type="submit" name="Submit" value="Search"></td>
  </tr>
</table>
</form>

  1. We'll also have to set up new <cfparam> statements for default values for these new form elements, at the top of the page:

<cfparam name="form.searchtype" default="0">
<cfparam name="form.daterange" default="0">

  1. We'll create two new variables and set their values depending on what is in the dropdown boxes:

<cfparam name="anyWords" default="false">
<cfparam name="exactPhrase" default="false">

<!---if the searchtype dropdown is for any words--->
<cfif form.searchtype eq "any">
  <cfset anyWords = "true">
</cfif>

<!---if the searchtype dropdown is for exact phrase--->
<cfif form.searchtype eq "exact">
  <cfset exactPhrase = "true">
</cfif>

  1. Lastly, we'll add the new arguments to the <cfinvoke> tag:

<cfinvoke
webservice="http://www.communitymx.com/services/cmxfeed.wsdl"
method="searchContent"
returnvariable="aObjectArray">
  <cfinvokeargument name="search" value=#form.search# />
  <cfinvokeargument name="anyWords" value=#anyWords# />
  <cfinvokeargument name="exactPhrase" value=#exactPhrase# />
  <cfinvokeargument name="contentType" value=#form.contentType# />
  <cfinvokeargument name="contentDate" value=#form.daterange# />
</cfinvoke>

Browse the page and it should now allow you to specify the type of search you want to perform as well as a date range.

The completed example can be seen here.

The page code can be viewed here (you might have to View Source in your browser).

Summary

Web services can be built easily in Dreamweaver MX, and ColdFusion programming techniques, such as looping through arrays, can be easily utilized. The CMX web service can be used to freshen the content on your own pages by offering new content links every day.

Bryan: I added a 4th example showing all arguments. I decided not to implement the sorting that you talked about because it would be very complicated given the structure of the .wsdl file. I will do this in my article about the RSS feed, which is similar to the MM feed. -- Tom