Sei sulla pagina 1di 6

<!--- Copyright 2007 Michael Horne - mike@recantha.co.uk - recantha.blogspot.

com
--->
<!--- Concept based on http://www.newsight.de/2005/10/19/datatypeconvert-v114-cfc-
update/ but substantially rewritten --->

<cfcomponent name="dataTypeConvert" hint="Convert data type to data type using


various functions">

<cffunction name="init" returntype="datatypeconvert" access="public">


<cfreturn this/>
</cffunction>

<cffunction name="QueryToStruct" access="public" returntype="struct"


hint="Converts a query to struct.">
<cfargument name="query" required="yes" type="query" hint="The
query to convert.">
<cfargument name="primaryKey" required="no" type="string" hint="Column
name that contains the primary key." default="">
<cfargument name="columnList" required="no" type="string" hint="Comma-
delimited list of the query columns." default="">

<cfset var local = structNew()>


<cfset local.result = structNew()>

<!--- determine query column names --->


<cfif Len(arguments.columnList)>
<cfset local.cols = Replace(arguments.columnList, " ", "")>
<cfelse>
<cfset local.cols = arguments.query.columnList>
</cfif>

<!--- remove primary key --->


<cfif Len(arguments.primaryKey)>
<cfset local.pkPosition = ListFindNoCase(local.cols,
arguments.primaryKey)>
<cfif local.pkPosition>
<cfset local.cols = ListDeleteAt(local.cols,
local.pkPosition)>
</cfif>
</cfif>

<cfset local.cols = ListToArray(local.cols)>

<!--- loop thru rows --->


<cfloop from="1" to="#arguments.query.recordCount#" index="local.i">
<cfif Len(arguments.primaryKey)>
<cfset local.key =
arguments.query[arguments.primaryKey][local.i]>
<cfelse>
<cfset local.key = local.i>
</cfif>

<cfset StructInsert(local.result, local.key, StructNew())>

<cfloop from="1" to="#ArrayLen(local.cols)#" index="local.n">


<!---cfoutput><p style="font-
weight:bold">#local.i#/#local.n#/#local.cols[local.n]# = #local.key# /
#arguments.query[local.cols[local.n]][local.i]#</p></cfoutput--->
<cfset StructInsert(local.result[local.key],
local.cols[local.n], arguments.query[local.cols[local.n]][local.i])>
</cfloop>
</cfloop>

<cfreturn local.result>
</cffunction>

<cffunction name="XmlToStruct" access="public" output="yes"


returntype="struct" hint="Converts a XML document object or a XML file to
struct.">

<!--- Function Arguments --->


<cfargument name="xmlObj" required="no" type="any" hint="Parsed XML
document object. Required if argument file is not set.">
<cfargument name="file" required="no" type="string" hint="Pathname
or URL of the XML file to read. Required if argument xmlObj is not set."
default="">
<cfargument name="charset" required="no" type="string" default="UTF-8"
hint="The character encoding in which the XML file contents is encoded.">

<cfset var local = structNew()>


<cfset local.dataStruct = StructNew()>
<cfset local.debug = false>

<!--- if passed in filename, read the file in --->


<cfif Len(arguments.file)>
<cfset local.xmlData = XmlParseFile(arguments.file,
arguments.charset)>
<cfelse>
<cfset local.xmlData = arguments.xmlObj>
</cfif>

<!--- local.xmlData now contains the XML data in CF format --->


<!--- skip the xmlRoot element --->
<cfif StructKeyExists(local.xmlData, "xmlRoot")>
<cfset StructInsert(local.dataStruct,
local.xmlData.xmlRoot.xmlName, XmlToStruct(local.xmlData.xmlRoot))>
<cfset local.dataStruct[local.xmlData.xmlRoot.xmlName].attributes
= StructNew()>
<!--- record attributes --->
<cfloop
list="#StructKeyList(local.xmlData.xmlRoot.xmlAttributes)#" index="local.attr">
<cfset
StructInsert(local.dataStruct[local.xmlData.xmlRoot.xmlName].attributes,
local.attr, local.xmlData.xmlRoot.xmlAttributes[local.attr])>
</cfloop>
<cfelse>
<!--- Set parent text to dataStruct --->
<!--- next line removes special characters - you will need to do
this yourself --->
<cfset local.parentName =
UCase(getFactory().get("stringUtil").util.stripSpecial(local.xmlData.xmlName))>
<cfset local.parentText = Trim(local.xmlData.xmlText)>
<cfset local.childrenCount = ArrayLen(local.xmlData.xmlChildren)>

<cfif local.debug>
<cfoutput><h1>#local.parentName# / #local.parentText# /
#local.childrenCount#</h1></cfoutput>
</cfif>

<cfloop from="1" to="#local.childrenCount#" index="local.i">


<cfset local.name =
local.xmlData.xmlChildren[local.i].xmlName>
<cfset local.text =
local.xmlData.xmlChildren[local.i].xmlText>
<cfset local.tmpChildData =
local.xmlData.xmlChildren[local.i].xmlChildren>

<cfif local.debug>
<cfoutput><h2>Child #local.i#: #local.name# /
#local.text#</h2></cfoutput>
</cfif>

<cfset local.items = structNew()>


<!--- loop through child items --->
<cfloop from="1"
to="#ArrayLen(local.xmlData.xmlChildren[local.i])#" index="local.c">
<cfset local.child =
local.xmlData.xmlChildren[local.i][local.c]>
<cfif local.debug>
<cfoutput><p>Sub-child #local.c#</p></cfoutput>
</cfif>
<cfif ArrayLen(local.child.xmlChildren)>
<cfset local.tmpChildConvert =
xmlToStruct(local.child)>
<cfif StructCount(local.tmpChildConvert) ge 1>
<cfloop
list="#StructKeyList(local.tmpChildConvert)#" index="local.key">
<cfif
isStruct(local.tmpChildConvert[local.key]) AND
StructCount(local.tmpChildConvert[local.key]) eq 1>
<cfset
StructInsert(local.items, local.key, local.tmpChildConvert[local.key][local.key])>
<cfelse>
<cfset
StructInsert(local.items, local.key, local.tmpChildConvert[local.key])>
</cfif>
</cfloop>
<cfelse>
<!--- pick-up of branch end --->
<cftry>
<cfset StructInsert(local.items,
local.child.xmlName, local.tmpChildConvert[local.child.xmlName])>
<cfcatch type="any">
<cfdump var="#local.items#">
<cfdump var="#local.child#">
<cfdump
var="#local.tmpChildConvert#">
<cfabort>
</cfcatch>
</cftry>
</cfif>
<cfelse>
<!--- branch end --->
<cfset StructInsert(local.items,
local.child.xmlName, Trim(local.child.xmlText))>
</cfif>
</cfloop>

<cfif local.debug>
<cfoutput><hr></cfoutput>
</cfif>

<!--- We don't want to nest identical struct keys.


So, we check to see if there is only a single element
in the items struct,
then check to see if that single key is the same as
local.name, the name of the parent.
If they are the same, we knock a level out by
inserting the (single) value in the items struct
rather than the struct itself.
--->

<cfif NOT StructKeyExists(local.dataStruct, local.name)>


<cfif StructCount(local.items) eq 1 AND
StructKeyList(local.items) eq local.name>
<cfset local.dataStruct[local.name] =
local.items[local.name]>
<cfelse>
<cfset StructInsert(local.dataStruct,
local.name, local.items)>
</cfif>
<cfelse>
<cfif NOT isArray(local.dataStruct[local.name])>
<!--- the current dataStruct has the local.name
key with an existing value, but only one --->
<!--- get the current value --->
<cfset local.tmpItem =
local.dataStruct[local.name]>
<!--- wipe over the value with an array and add
the old item back as an array element --->
<cfset local.dataStruct[local.name] =
ArrayNew(1)>
<cfset
ArrayAppend(local.dataStruct[local.name], local.tmpItem)>

<!--- add the current items struct to the array


--->
<cfif StructCount(local.items) eq 1 AND
StructKeyList(local.items) eq local.name>
<cfset
ArrayAppend(local.dataStruct[local.name], local.items[local.name])>
<cfelse>
<cfset
ArrayAppend(local.dataStruct[local.name], local.items)>
</cfif>
<cfelse>
<!--- already got an array there with at least
2 items in it, so just append--->
<cfif StructCount(local.items) eq 1 AND
StructKeyList(local.items) eq local.name>
<cfset
ArrayAppend(local.dataStruct[local.name], local.items[local.name])>
<cfelse>
<cfset
ArrayAppend(local.dataStruct[local.name], local.items)>
</cfif>
</cfif>
</cfif>

<!--- dump a specific item


<cfif local.debug AND local.name eq "promotion">
<cfdump var="#local.datastruct#">
</cfif> --->
</cfloop>
</cfif>

<cfreturn local.dataStruct>
</cffunction>

<!--- -------------------------------------------------- --->


<!--- RemoveInvalidChar --->
<cffunction name="RemoveInvalidChar" access="private" output="no"
returntype="string" hint="Replace all non-ascii characters from XML name.">

<!--- Function Arguments --->


<cfargument name="string" required="yes" type="string" hint="String
with the XML name.">

<cfscript>

arguments.string = Replace(arguments.string, ":", "_", "ALL");


// Replace character before prefix
arguments.string = REReplace(arguments.string, "[^[:ascii]]",
"_", "ALL"); // Replace all non-ascii character

/* Return string */
return arguments.string;

</cfscript>

</cffunction>

<cffunction name="ListDeleteDuplicates" access="private"


returnType="string">
<cfargument name="theList" type="string" required="true">
<cfargument name="delimiter" type="string" required="false"
default=",">

<cfset var local = StructNew()>

<cfset local.returnValue = "">


<cfset local.arrayList = ListToArray(arguments.theList,
arguments.delimiter)>

<cfloop from="1" to="#ArrayLen(local.arrayList)#" index="local.i">


<cfif NOT ListFind(local.returnValue, local.arrayList[local.i],
arguments.delimiter)>
<cfset local.returnValue = ListAppend(local.returnValue,
local.arrayList[local.i], arguments.delimiter)>
</cfif>
</cfloop>
<cfreturn local.returnValue>
</cffunction>

</cfcomponent>

Potrebbero piacerti anche