How To Move XML Data Into A Database Using ColdFusion

<!---
	Create an XML document. This could be something that
	is uploaded, read from a file, or created manually
	(as we are doing).
--->
<cfxml variable="data">
 
	<records>
 
		<record>
			<name>Tricia</name>
			<hair>Brunette</hair>
		</record>
 
		<record>
			<name>Joanna</name>
			<hair>Brunette</hair>
		</record>
 
		<record>
			<name>Eva</name>
			<hair>Blonde</hair>
		</record>
 
	</records>
 
</cfxml>
 
 
<!---
	When gathering data from an XML document, there are many ways
	to do it. You can loop over them via ColdFusion's pseudo node
	collections or, access the children using XML notation, or
	search for them (or use a combination of the above). Since the
	avilability of these methods depends in part on what version
	of ColdFusion you have, let's look at each methodology.
--->
 
 
<!--- ----------------------------------------------------- --->
<!--- ----------------------------------------------------- --->
 
 
<!---
	Method 1: XmlSearch().
	In this method, I am going to search for the "record" nodes.
	This will return an array of Record nodes.
--->
 
<!--- Get record nodes. --->
<cfset recordNodes = xmlSearch( data, "/records/record" ) />
 
<!---
	Loop over the nodes so that we can insert each one into
	the database.
--->
<cfloop
	index="recordNode"
	array="#recordNodes#">
 
	<!---
		Because XML notation is somewhat wordy, I sometimes like
		to create a short-hand to the target value before the
		query so that I can keep the query very readible.
 
		Because we are using XmlSearch() in this demo, I'm going
		to use it here to gather the text values from the nodes.
		This isn't the "right" approach, but I'll use it here to
		show all concepts.
	--->
	<cfset valueNodes = xmlSearch( recordNode, "./*/text()" ) />
 
	<!---
		Because xmlSearch() returns the nodes in the same order
		that they appear in the XML document (which we assume is
		uniform), we can get the values based on their order.
	--->
	<cfset girlName = valueNodes[ 1 ].xmlValue />
 
	<!---
		You can also use xmlSeach() to search by the value node
		by its name. I will get the hair value in this way.
 
		Because xmlSearch() returns an array, we have to store an
		intermediary collection value.
	--->
	<cfset hairNodes = xmlSearch( recordNode, "./hair/text()" ) />
	<cfset hairColor = hairNodes[ 1 ].xmlValue />
 
	<!--- Insert the values into the database. --->
	<cfquery name="insert" datasource="ben">
		INSERT INTO xml_girl
		(
			name,
			hair
		) VALUES (
			<cfqueryparam value="#girlName#" cfsqltype="cf_sql_varchar" />,
			<cfqueryparam value="#hairColor#" cfsqltype="cf_sql_varchar" />
		);
	</cfquery>
 
</cfloop>
 
 
<!--- ----------------------------------------------------- --->
<!--- ----------------------------------------------------- --->
 
 
<!---
	Method 2: Native XML DOM.
	In this method, I am going to walk over the XML DOM (Document
	Object Model) using native XML navigation (specifically things
	like XmlChildren and XmlText).
--->
 
<!---
	We know the structure of the XML document so we know that the
	record nodes are the direct children of the root node. There-
	fore, we can loop over the first set of children.
--->
<cfloop
	index="recordNode"
	array="#data.xmlRoot.xmlChildren#">
 
	<!---
		Just as before, we are going to be getting short hand
		references to your XML values. However, this time, rather
		than using xmlSearch(), we are simply going to refer to
		the child nodes by the xmlChildren collection and the
		appropriate index.
	--->
	<cfset girlName = recordNode.xmlChildren[ 1 ].xmlText />
	<cfset hairColor = recordNode.xmlChildren[ 2 ].xmlText />
 
	<!--- Insert the values into the database. --->
	<cfquery name="insert" datasource="ben">
		INSERT INTO xml_girl
		(
			name,
			hair
		) VALUES (
			<cfqueryparam value="#girlName#" cfsqltype="cf_sql_varchar" />,
			<cfqueryparam value="#hairColor#" cfsqltype="cf_sql_varchar" />
		);
	</cfquery>
 
</cfloop>
 
 
<!--- ----------------------------------------------------- --->
<!--- ----------------------------------------------------- --->
 
 
<!---
	Method 3: ColdFusion Pseudo XML Collections.
	As a convenience, ColdFusion provides pseudo collections of
	XML nodes such that they can be referenced by name. In this
	method, we are going to walk over these collections.
--->
 
<!---
	We know the structure of the XML document so we know that
	the record nodes are the direct children of the records node.
	Therefore, we can use the named path to find the target
	record nodes.
--->
<cfloop
	index="recordIndex"
	from="1"
	to="#arrayLen( data.records.record )#"
	step="1">
 
	<!---
		Since we can't loop over these ColdFusion psuedo XML
		node collection using an array-loop, we have to use an
		index loop. As such, I generally like to get a short-
		hand reference to the node at the current index.
	--->
	<cfset recordNode = data.records.record[ recordIndex ] />
 
	<!---
		Now that we have the current record node, I am going to
		grab the value of the given value nodes.
 
		NOTE: Even when working with the pseudo collections, we
		STILL HAVE TO use the xmlText attribute (otherwise
		ColdFusion will convert the node to a string, giving it
		a doctype).
 
		NOTE: We can exclude the index of the value node (ex.
		recordNode.name[ 1 ]) because we only want the first one
		which is what not include the index defaults to. You can
		use the [ 1 ], if you want, as I have done with hair.
	--->
	<cfset girlName = recordNode.name.xmlText />
	<cfset hairColor = recordNode.hair[ 1 ].xmlText />
 
	<!--- Insert the values into the database. --->
	<cfquery name="insert" datasource="ben">
		INSERT INTO xml_girl
		(
			name,
			hair
		) VALUES (
			<cfqueryparam value="#girlName#" cfsqltype="cf_sql_varchar" />,
			<cfqueryparam value="#hairColor#" cfsqltype="cf_sql_varchar" />
		);
	</cfquery>
 
</cfloop>

For Cut-and-Paste