A Simple XML Component

Posted on Mar 30, 2005

The code that I am posting here forms the basis for a ColdFusion Component to maintain an employee list in XML. This comes from a project at work which does something a little more logical than maintain an employee list in XML (but I cannot share the original code). However, this can be useful for a number of projects and therefore I am posting a generalized version of the code for anyone to use.The basics of the component are that it adds employees (with attributes) to a simple xml object. It allows you to edit a particular item, delete a particular item and convert the entire xml object into a query. All of this is done using a unique employeeID for simplicity, but you could modify this application to be more robust (and create additional components to persist the xml somehow as well). Enough said...here is the code:

<cfcomponent name="employee">

   <cffunction name="init" access="public" output="false" returntype="employee">
      <cfargument name="xmlString" type="string" required="false">
      
      <cfscript>
         // parse the xml if an existing was supplied          if (isDefined("arguments.xmlString")) {
            variables.empStruct = xmlParse(xmlString);
         }
         // if not, create the empty xml structure          else {
            variables.empStruct = xmlNew();
            variables.empStruct.xmlRoot = xmlElemNew(empStruct,"employees");
         }
         return this;
      </cfscript>
   </cffunction>
   
   <cffunction name="addItem" access="public" output="false" returntype="void">
      <cfargument name="employeeID" type="string" required="true">
      <cfargument name="lastName" type="string" required="false" default="">
      <cfargument name="firstName" type="string" required="false" default="">
      <cfargument name="xmlText" type="string" required="false" default="">
      <cfargument name="dateAdded" type="date" required="false" default="#now()#">
      
      <cfscript>
         var i = 0;
         // search to see if that employeeID already exists          var objItemToAdd = xmlSearch(variables.empStruct,"//employee[@EMPLOYEEID='#arguments.employeeID#']");          // if the item does not already exist, add it          if (arrayLen(objItemToAdd) EQ 0) {
            // append the child element and populate the attributes and xmltext             arrayAppend(variables.empStruct.employees.XmlChildren,XmlElemNew(empStruct,"employee"));
            i = arrayLen(variables.empStruct.employees.XmlChildren);
            variables.empStruct.employees.XmlChildren[i].xmlAttributes.lastName = arguments.lastName;
            variables.empStruct.employees.XmlChildren[i].xmlAttributes.firstName = arguments.firstName;
            variables.empStruct.employees.XmlChildren[i].xmlAttributes.employeeID = arguments.employeeID;
            variables.empStruct.employees.XmlChildren[i].xmlAttributes.dateAdded = arguments.dateAdded;
            variables.empStruct.employees.XmlChildren[i].xmlText = arguments.xmlText;
         }
      </cfscript>
   </cffunction>
   
   <cffunction name="editItem" access="public" output="false" returntype="void">
      <cfargument name="employeeID" type="numeric" required="true">
      <cfargument name="lastName" type="numeric" required="false">
      <cfargument name="firstName" type="string" required="false" default="">
      <cfargument name="xmlText" type="string" required="false">
      <cfargument name="dateAdded" type="date" required="false">
      <cfscript>
         // search according to employeeID          var objItemToEdit = xmlSearch(variables.empStruct,"//employee[@EMPLOYEEID='#arguments.employeeID#']");          // if edits were supplied to the attributes, set them          if (isDefined("arguments.lastName")) {
            objItemToEdit[1].xmlAttributes.lastName=arguments.lastName;
         }
         if (isDefined("arguments.firstName")) {
            objItemToEdit[1].xmlAttributes.firstName=arguments.firstName;
         }
         if (isDefined("arguments.xmlText")) {
            objItemToEdit[1].xmlText=arguments.xmlText;
         }
         if (isDefined("arguments.dateAdded")) {
            objItemToEdit[1].xmlAttributes.lastName=arguments.dateAdded;
         }
      </cfscript>
   </cffunction>
   
   <cffunction name="deleteItem" access="public" output="false" returntype="void">
      <cfargument name="employeeID" type="numeric" required="true">
      
      <cfscript>
         // search for the item to delete and then clear it          var objItemToDelete = xmlSearch(variables.empStruct,"//employee[@EMPLOYEEID='#arguments.employeeID#']");          arrayClear(objItemToDelete[1]);
         arrayDeleteAt(objItemToDelete, 1);
      </cfscript>
   </cffunction>
   
   <cffunction name="toQuery" access="public" output="false" returntype="query">
      <cfscript>
         var i = 0;
         // create the empty query          var returnQry = queryNew("employeeID,lastName,firstName,dateAdded,comments");
         // loop through the xml elements and use their values to populate the query rows          for (i=1;i LTE arrayLen(variables.empStruct.employees.XmlChildren);i=i+1) {
            queryAddRow(returnQry);
            querySetCell(returnQry,"employeeID",variables.empStruct.employees.XmlChildren[i].xmlAttributes.employeeID);
            querySetCell(returnQry,"lastName",variables.empStruct.employees.XmlChildren[i].xmlAttributes.lastName);
            querySetCell(returnQry,"firstName",variables.empStruct.employees.XmlChildren[i].xmlAttributes.firstName);
            querySetCell(returnQry,"dateAdded",variables.empStruct.employees.XmlChildren[i].xmlAttributes.dateAdded);
            querySetCell(returnQry,"comments",variables.empStruct.employees.XmlChildren[i].xmlText);
         }
         return returnQry;
      </cfscript>
   </cffunction>
   
   <cffunction name="getEmpStruct" access="public" output="false" returntype="xml">
      <cfreturn variables.empStruct>
   </cffunction>
</cfcomponent>

Here is a basic page that shows how you might use the methods supplied within the component to create your employee list:

<cfcontent reset="true">
<cfsetting showdebugoutput="false">
<cfsavecontent variable="testXml"><?xml version="1.0" encoding="UTF-8"?><employees><employee DATEADDED="{ts '2005-03-29 14:02:54'}" LASTNAME="Rinaldi" FIRSTNAME="Rinaldi" EMPLOYEEID="99999">this employee was added during initialization</employee></employees></cfsavecontent>

<cfscript>
   // test the init with xml from above to prepopulate    objWL = createObject("component","employee").init(testXml);
   // test add employees    objWL.addItem(11111,"Hicks","Shannon");
   // test adding the same employee twice (should only add one)    objWL.addItem(11111,"Hicks","Shannon");
   objWL.addItem(22222,"Pease","Shannon","freedom fries");
   objWL.addItem(98979,"Feyrer","Chris","this employee will be deleted");
   // test edit item    objWL.editItem(employeeID=98979,xmlText="this employee has been edited");
   // test delete an item    objWL.deleteItem(22222);
</cfscript>

<cfdump var="#objWL.getEmpStruct()#">
<cfdump var="#objWL.toQuery()#">
<cfabort>

As usual, hopefully this is useful to someone (as it once would have been to me!). Enjoy!

Comments

johnny So, what would the form-side of this look like?

Posted By johnny / Posted on 01/05/2006 at 1:34 PM


Brian Rinaldi There really isn't anything special about the form for this...just a standard form would work. You would do your validation and then (if everything is ok) do something like objWL.addItem(form.id,form.lastName,form.firstName,form.description);

Posted By Brian Rinaldi / Posted on 01/09/2006 at 8:53 PM


Write your comment



(it will not be displayed)





About

My name is Brian Rinaldi and I am the Web Community Manager for Flash Platform at Adobe. I am a regular blogger, speaker and author. I also founded RIA Unleashed conference in Boston. The views expressed on this site are my own & not those of my employer.