<cfset a.b["c.d.e.f"] = 1>
<cfoutput>#a.b.c.d.e.f#</cfoutput>
Railo will throw the error:key [C] doesn't exist in struct (keys:c.d.e.f)
So Railo will display what keys are in that struct and you see it listed. The only key inside b is c.d.e.f. Here's why:
CF8 (for instance) will look for the following (in Pseudocode=:
IF variables scope contains key "a.b.c.d.e.f"
display the variables["a.b.c.d.e.f"]
ELSEIF variables scope contains key "a"
If variables["a"] contains key "b"
IF variables["a"]["b"] contains key "c"
IF variables["a"]["b"]["c"] contains key "d"
IF variables["a"]["b"]["c"]["d"] contains key "e"
IF variables["a"]["b"]["c"]["d"]["e"] contains key "f"
Display variables["a"]["b"]["c"]["d"]["e"]["f"]
ELSE
THROW ERROR
END
ELSEIF variables["a"]["b"]["c"]["d"] contains key "e.f"
Display variables["a"]["b"]["c"]["d"]["e.f"]
ELSE
THROW ERROR
END
...
ELSEIF variables["a"]["b"] contains key "c.d.e.f"
Display variables["a"]["b"]["c.d.e.f"]
ELSE
THROW ERROR
END
...
END
So only the red if case get's involved. You see, there is a lot to do in CF8. This is of course much more flexible, but on the other hand it is slow. In addition the term a.b.c.d.e.f is misleading as well. It suggerates that a contains a key b that contains a key c etc. Which is not the case. A contains a key b and b contains a key c.d.e.f. Respecting the above we did not implement this implicit searching for struct keys since it is very slow and would only affect less than .1% of all the structs and in addition is misleading.
OK. This said, here's another thing why it is misleading. Just try to dump the following in CF8:
<cfdump var="#a.b.c.d#">Normally you would expect to see a struct containing something. But correctly CF throws an error.
The problem occured for example in cffm by Rick Root. There some resource keys are defined in the resource file cffm.properties like this: msg.t1, msg.t2 etc. Then JavaRB is used in order to place them in a struct called cffm.resourceKit. Since JavaRB reads the message names as keys an addressing inside cffm like this: cffm.resourceKit.errorMsg.t11 will throw an error in Railo. What you would have to do in cffm is to call the struct like this: cffm.resourceKit["errorMsg.t11"]. This would work in CF8 and in Railo as well. If you would dump the struct: cffm.resourceKit.errorMsg both Railo and CF8 would throw an error.
Now, what I did in order to solve the problem for CFFM is, that I added the following small function to cffm:
<cffunction name="dotNotation2Struct" output="No" returntype="struct">
<cfargument name="resourceKit" type="struct" required="Yes">
<cfset var key = "">
<cfset var dotKey = "">
<cfset var st = arguments.resourceKit>
<cfset var sOldKey = "">
<cfloop collection="#arguments.resourceKit#" item="dotKey">
<cfset st = arguments.resourceKit>
<cfset sOldKey = "">
<cfloop list="#dotKey#" index="key" delimiters=".">
<cfif sOldKey neq "">
<cfset st = st[sOldKey]>
</cfif>
<cfif not structKeyExists(st, key)>
<cfset st[key] = structNew()>
</cfif>
<cfset sOldKey = key>
</cfloop>
<cfset st[sOldKey] = arguments.resourceKit[dotKey]>
<cfset structDelete(arguments.resourceKit, dotKey)>
</cfloop>
<cfreturn arguments.resourceKit>
</cffunction>The above code converts all key that contain a "." in their keyname into a corresponding struct. This for instance is done in CFFM in the file cffm.cfm like follows:
variables.resourceKit = dotNotation2Struct(variables.rbm.getResourceBundle("#variables.rbFile#","#variables.defaultJavaLocale#"));After this line of code CFFM ran flawlessly and now even understands Railo resources like FTP or Amazon S3. So I was able to use CFFM in order to browse through my FTP accounts. I just added a mapping that points to my ftp account like: /ftp -> ftp://username:password@ftpserver/ and added it to the folders that can be browsed with cffm. Somewhere there is a line inside cffm.cfm that looks like this:
<cfinvokeargument name="includeDir" value="c:\...">
You can now replace it with a mapping you created in the Railo administrator.
...
<cfinvokeargument name="includeDir" value="/ftp">
OR
<cfinvokeargument name="includeDir" value="/s3">
OR
<cfinvokeargument name="includeDir" value="/ram">
...
Then I can use CFFM to work with these external file systems even though cffm knows nothing about ftp or s3.
8 responses so far ↓
1 ike // Nov 17, 2008 at 9:31 PM
2 Michael Streit // Nov 18, 2008 at 10:15 AM
isDefined('a.b.c.d'):false
isDefined('variables.a.b.c.d'):false
isDefined('variables["a.b.c.d"]'):true
structKeyExists(variables,'a'):false
structKeyExists(variables,'a.b'):false
structKeyExists(variables,'a.b.c.d'):true
and now how CFMX does
isDefined('a.b.c.d'):true
isDefined('variables.a.b.c.d'):true
isDefined('variables["a.b.c.d"]:throw->must be a syntactically valid variable name
structKeyExists(variables,'a'):false
structKeyExists(variables,'a.b'):false
structKeyExists(variables,'a.b.c.d'):true
like you can see in cfmx the structKeyExists function work the same way as in Railo,
because there is no key with name "a" or "a.b", the only key that exists is "a.b.c.d"
isDefined works not the same way, because isDefined does not look for keys, it checks for variables.
isdefined is more like the following
function _isDefined(str){
try{
evaluate(str);
return true;
}
catch(e){}
return false;
}
and for cfmx the variable "a.b.c.d" exists.
3 Michael Streit // Nov 20, 2008 at 1:18 PM
example:
<cfset variables['a.b.c']=1>
<pre>
<cfoutput>before: #variables.toString()#</cfoutput>
<cfset structKeyTranslate(variables)>
<cfoutput>after: #variables.toString()#</cfoutput>
</pre>
output:
before: {a.b.c={1}}
after: {a={{b={{c={1}}}}}}
we have also add 2 addional attributes
- boolean deepTranslation do also translate the children of the struct
- boolean leaveOriginalKey leave the original key in the struct
example:
<cfset variables['a.b.c']=1>
<pre>
<cfoutput>before: #variables.toString()#</cfoutput>
<cfset structKeyTranslate(variables,false,true)>
<cfoutput>after: #variables.toString()#</cfoutput>
</pre>
output:
before: {a.b.c={1}}
after: {a={{b={{c={1}}}}}, a.b.c={1}}
4 Snake // Nov 20, 2008 at 4:16 PM
5 Gerald Guido // Nov 24, 2008 at 9:30 PM
6 Gert Franz // Nov 25, 2008 at 3:50 PM
don't understand your comment, could you explain it a little?
7 Gerald Guido // Nov 25, 2008 at 4:04 PM
Plus
http://www.coldfusioncamp.com/en/index.cfm
Equals an early Christmas? No?
8 Gert Franz // Nov 25, 2008 at 4:13 PM
Since we cannot make a first impression twice we would rather make it a good one... That's why we are taking our time.
Gert
Leave a Comment