Well, this simple solution was created for cffeed, but your problem is very similar.
At first I tried to use the Java library StringEscapeUtils (Commons Lang API), but it did not work properly. Although it is recommended for XML.
So this cfc method works for me. Perhaps it will help you too.
<cffunction name="cleanXmlString" access="public" returntype="any" output="false" hint="Replace non-valid XML characters">
<cfargument name="dirty" type="string" required="true" hint="Input string">
<cfset var cleaned = "" />
<cfset var patterns = "" />
<cfset var replaces = "" />
<cfset patterns = chr(8216) & "," & chr(8217) & "," & chr(8220) & "," & chr(8221) & "," & chr(8212) & "," & chr(8213) & "," & chr(8230) />
<cfset patterns = patterns & "," & chr(1) & "," & chr(2) & "," & chr(3) & "," & chr(4) & "," & chr(5) & "," & chr(6) & "," & chr(7) & "," & chr(8) />
<cfset patterns = patterns & "," & chr(14) & "," & chr(15) & "," & chr(16) & "," & chr(17) & "," & chr(18) & "," & chr(19) />
<cfset patterns = patterns & "," & chr(20) & "," & chr(21) & "," & chr(22) & "," & chr(23) & "," & chr(24) & "," & chr(25) />
<cfset patterns = patterns & "," & chr(26) & "," & chr(27) & "," & chr(28) & "," & chr(29) & "," & chr(30) & "," & chr(31) />
<cfset replaces = replaces & "',',"","",--,--,..." />
<cfset replaces = replaces & ",-, , , , , , , " />
<cfset replaces = replaces & ", , , , , , " />
<cfset replaces = replaces & ", , , , , , " />
<cfset replaces = replaces & ", , , , , , " />
<cfset cleaned = ReplaceList(arguments.dirty, patterns, replaces) />
<cfreturn cleaned />
</cffunction>