Recursive ColdFusion Custom Tag Example

<!--- Kill extra output. --->
<cfsilent>
 
	<!---
		This is the XML object that is going to be
		displayed. This might be an XML document or
		it might be an XML node.
	--->
	<cfparam
		name="ATTRIBUTES.Xml"
		type="xml"
		/>
 
	<!---
		This is the depth of the XML node. We will
		need this to indent the XML node on output.
	--->
	<cfparam
		name="ATTRIBUTES.Depth"
		type="numeric"
		default="0"
		/>
 
 
 
	<!---
		Check to see if the passed in XML object was
		a document. If it is, then grab the root node
		reference and store that back into the attribute.
	--->
	<cfif IsXmlDoc( ATTRIBUTES.Xml )>
 
		<!--- Get the root node reference. --->
		<cfset ATTRIBUTES.Xml = ATTRIBUTES.Xml.XmlRoot />
 
	</cfif>
 
 
	<!---
		ASSERT: At this point, no matter what type of
		XML data was passed into the custom tag, the
		ATTRIBUTES.Xml variable now points to an XML
		document node.
	--->
 
 
	<!--- Create a string for the current depth. --->
	<cfset strDepth = RepeatString(
		"&nbsp;&nbsp;&nbsp;&nbsp;",
		ATTRIBUTES.Depth
		) />
 
	<!--- Create a string for the next depth. --->
	<cfset strNextDepth = RepeatString(
		"&nbsp;&nbsp;&nbsp;&nbsp;",
		(ATTRIBUTES.Depth + 1)
		) />
 
</cfsilent>
 
<cfoutput>
 
	<!--- Output the open node tag. --->
	#strDepth#
	&lt;#ATTRIBUTES.Xml.XmlName#&gt;<br />
 
		<!---
			Check to see if this node has child nodes. If it
			does, we are going to recurse through those. If
			not, we are just going to display the node text.
		--->
		<cfif ArrayLen( ATTRIBUTES.Xml.XmlChildren )>
 
			<!---
				Loop over the XML children and send each
				one recursively to this tag.
			--->
			<cfloop
				index="intI"
				from="1"
				to="#ArrayLen( ATTRIBUTES.Xml.XmlChildren )#"
				step="1">
 
				<!---
					Call the current tag, but this time, pass
					in the given child of the current XML node.
				--->
				<cfmodule
					template="./showxml.cfm"
					xml="#ATTRIBUTES.Xml.XmlChildren[ intI ]#"
					depth="#(ATTRIBUTES.Depth + 1)#"
					/>
 
			</cfloop>
 
		<cfelse>
 
			<!---
				Output the node text. When outputing this
				value, use the NEXT node depth as the text
				will be indented beyond the current tag.
			--->
			#strNextDepth#
			#ATTRIBUTES.Xml.XmlText#<br />
 
		</cfif>
 
	<!--- Output the close node tag. --->
	#strDepth#
	&lt;/#ATTRIBUTES.Xml.XmlName#&gt;<br />
 
</cfoutput>
 
<!---
	Exit out to the tag. We only need to fire
	the open tag. We don't care about any duplicate,
	close tag functionality.
--->
<cfexit method="EXITTAG" />

For Cut-and-Paste