Showing posts with label bugs. Show all posts
Showing posts with label bugs. Show all posts

Wednesday, July 22, 2009

Using ColdFusion to add XML data to a SQL database

Using the ColdFusion XML document object can present some unexpected challenges when updating databases. Variable references to elements in this structure do not return values as one might expect but instead return new structures. Useful ColdFusion functions such as <cfoutput> resolve these new structures into values behind the scene, which can mislead you when trying to debug wrong values being placed into the database.

As an example, consider the following. An xml file has a field named ICN, among others. We will read the file and update a SQL database. First, we get a file handle.

< cffile variable="gmrXML" file=" “wits.xml" action="read">

Then a ColdFusion XML Document Object datatype, using our file handle and the ColdFusion xmlParse() function:

< cfset myxml=" xmlParse(gmrXML)">

When we use cfoutput to see what we have, all is well:

<cfoutput>
<cfloop to="#arrayLen(myXML.incidentList.Incident)#" from="1" index="i">

#myXml.incidentlist.incident[i].ICN#


The output on our Web page shows the ICN value we expect:

200458431

Good enough. We now add it to our database with the following code:

<cfquery datasource="SMC" name="loadSMC">
Insert into aIncident(ICN)
values(#myXml.incidentlist.incident[i].ICN#
< /cfquery>


and when we look, the value in the ICN column in the database is not 200458431 but instead is

<?xml version="1.0"?>

This disappointing result is because in the cfquery above, we were treating the ICN reference as a value. cfouput helped in this deception because we could treat it as a value with this sophisticated function. A look at cfdump shows what happened.

Here is a dump of the reference:



It is not a value but a structure. To get to the value we want, we need to add .xmlText to the end of the reference we used so that the query now looks like:

<cfquery datasource="SMC" name="loadSMC">
Insert into aIncident(ICN)
values(#myXml.incidentlist.incident[i].ICN.xmlText#
</cfquery>

This works as expected.

Monday, July 20, 2009

ColdFusion Program to Read XML File

Markup encodes and transfers metadata about information such as its structure and format. XML is a markup language, derived from the much earlier SGML, which uses strings of short words to surround the data it is describing. These strings of short words are known as tags. An example would be <name>George</name> <phone>555-1212</phone>.

With XML, a structural model of the data in a file can be encoded along with the data. The structure can be as simple as name and phone or much more complex, with fields like name and phone embedded in other fields like employee. A style sheet, an XSL, can be used to transform the tagged data in an XML file into a Web page. Likewise, a schema file, an XSD, can communicate database information in database operations.

ColdFusion provides a subset of functions that enable a programmer to operate on XML files. A typical operation would be to read an XML file, work on it and write it, perhaps to a database. A datatype in ColdFusion has been created for XML and is known as the XML document object. By doing this, Adobe extends the reach of its already existing ColdFusion structure functions to encompass XML data as well.

Structures consist of objects, properties, and objects embedded in other objects. Name and phone embedded in employee is an example. The dot operator is used to delimit what object in a structure you want to access. The general syntax is <object>.<object>, <object>.<property>. These can be combined to get for instance <object>.<child object>.<property>, so to access my phone number, we would use the dot operator: <employee>.<phone>

The following ColdFusion code uses some of the XML functions to read an XML file. It starts by validating the XML data file to ensure that it is consistent with its schema.

<cfset myResults= XMLValidate ("wits.xml", "wits.xsd")>
<cfoutput> Is Valid? #myResults.status#!
</cfoutput>


Next, a file handle is obtained.

<cffile variable="gmrXML" file=" “wits.xml" action="read">

Then we get a ColdFusion XML Document Object datatype using our file handle and the xmlParse() function:

<cfset myxml=" xmlParse(gmrXML)">

Now we are ready to loop through the data, and display different field values. This test file consists of a series of incidents embedded in an incident list. In addition to its own properties, an incident will have an embedded list, or object, of one or more incident types. In addition to this, it will have, an embedded facilities list, of zero or more facilities involved in the incident. These embedded lists correspond to embedded objects or to child tables in a database.


<cfoutput>
<cfloop index="i" from="1" to="#arrayLen(myXML.incidentList.Incident)#">
Incident<br>
#myXml.incidentlist.incident[i].ICN#<br>
#myXml.incidentlist.incident[i].Subject#<br>
#myXml.incidentlist.incident[i].Summary#<br>
#myXml.incidentlist.incident[i].IncidentDate#<br>
Event Type<br>
<!---Here is an inner loop to get all Event Types for the Incident--->
<cfloop index="j" from="1" to=
"#arrayLen(myXML.incidentList.Incident[i]. EventTypeList.EventType)#">
#myXml.incidentlist.incident[i].EventTypeList.EventType[j]#<br>
</cfloop>
<br>Facilities<br>
<cfif StructKeyExists(myXml.incidentlist.incident[i].FacilityList,"Facility")>
<!---Here is an inner loop to get all Facilities for the Incident--->
<cfloop index="j" from="1" to
"#arrayLen(myXML.incidentList.Incident[i]. FacilityList.Facility)#">
#myXml.incidentlist.incident[i].FacilityList.Facility[j].FacilityType#<br>
#myXml.incidentlist.incident[i].FacilityList.Facility[j].Indicator#<br>
</cfloop>
<cfelse>
No facility for this one
</cfif>
</cfloop>
</cfoutput>



The ColdFusion arraylen is used in the “To” parameter of our loop to return the number of Incidents in this incidentlist. There is one incidentlist per file. Our dot operator starts with the file handle, then refers to the incidentlist we know to be in file (because we validated), and the particular incident is referenced with our index variable [i]:

myXml.incidentlist.incident[i].ICN

The incident number property, ICN, is accessed from the record just read from the file. For EventType, it is very similar. Since we know we will have at least one Event Type in every incident (one or more), the following code is sufficient:

myXml.incidentlist.incident[i].EventTypeList.EventType[j]

On the other hand, we may not have a facility (zero or more) and will get a null pointer exception if we try to dereference a facility in an empty facilitylist. We need to use the ColdFusion StructKeyExists function to test if a facility object is embedded in the facilitylist for the current record.

<cfif StructKeyExists(myXml.incidentlist.incident[i].FacilityList,"Facility")>

If so, then we loop through the facilities involved in the incident, else we indicate no facility.