Monday, September 23, 2002

Building XML dynamically with CFXML

Some may know that they can create XML dynamically in CF, just like creating HTML, by outputting the elements such as within query loops, etc. Here's an example:
<CFQUERY NAME="getemps" DATASOURCE="cfsnippets">
   SELECT *
   FROM Employees
</CFQUERY>

<cfxml variable="employees">
<Employees>
<cfloop query="getemps">
   <Employee>
      <cfoutput>
      <Emp_ID>#getemps.emp_id#</Emp_ID>
      <FirstName>#getemps.firstname#</FirstName>
      </cfoutput>
   </Employee>
</cfloop>
</Employees>
</cfxml>

<cfdump var="#employees#">

While you could do the same sort of thing in CF5, I've added above something that's specific to CFMX. Note that the creation of the XML elements is done inside a CFXML tag. This causes CFMX to create the XML as an internal XML object, stored in the named variable ("employees", above). Doing this allows us to treat the XML as a first class XML object with a variety of internal variables and controls built-into CFMX. See the chapter on working with XML in the "Developing CFML Apps with CFMX" manual.

When building XML this way, however, it can be challenging if you make the slightest mistake. :-) I have a few generic tips:


  • make sure that matching opening and closing xml elements are the same case
  • when building XML dynamically, it's possible that the source of the data may provide values that are inappropriate for use within XML (special characters, or worse, possibly including brackets that are interpreted as elements themselves. You should wrap such dynamic data in an XMLFormat function.
  • when stumped, you might want to replace the CFXML tags with CFSAVECONTENT (no other changes needed) and try outputting that for debugging purposes. While it would seem that using tostring against the xml object would provide the same result, since the SAVECONTENT doesn't really invoke the underlying XML processing, you might see something in outputting that which would cause an error in CFXML processing. This may be especially valuable if you're building the actual XML element names dynamically
  • while minimizing whitespace has some value, it might also help to render the source code with normal indenting (as I have above) to help give visual cues as to whether things are coded as expected
  • try stripping out parts of the process to minimize it and make sure that outer portions of the XML generation process are indeed what you think it to be

    Finally, someone may wonder how to simply dump all the contents of a table into XML without needing to spell out the column names. The concepts are again similar to outputting HTML:

    <cfxml variable="employees">
    <Employees>
    <cfloop query="getemps">
       <Employee>
       <cfloop list="#getemps.ColumnList#" index="field">
          <cfoutput>
          <#field#>
             #xmlformat(getemps[field][currentrow])#
          </#field#>
          </cfoutput>
       </cfloop>
       </Employee>
    </cfloop>
    </Employees>
    </cfxml>

    <cfdump var="#employees#">


No comments: