coldfusion splitting a loop with an include - loops

Here is some code:
<!---this is identical in several programs --->
<cfset i = 0>
<cfoutput>
<cfloop array = "#colvalue#" index = "val">
<cfset i = i + 1>
<cfset fieldname = colarr[i]>
<cfset modnum = i%basenum>
<script>
putval2('#val#', '#i#')
</script>
<!--- stuff which is different in each program --->
</cfloop>
</cfoutput>
This is working fine.
I put the identical code into a separate module called putback.cfm and rewrote this as:
<cfinclude template = "putback.cfm">
<!---stuff which is different in each program --->
</cfloop>
I got the error message "No matching start tag for end tag [cfloop]".
I thought the include meant that "putback.cfm" would be picked up and dumped into that spot in the program. But since it is not recognizing that the end tag cfloop goes with with beginning cfloop in putback.cfm, apparently it is not as transparent a process as I have understood.
Can anyone explain why this is not working and/or offer a workaround.

I thought the include meant that "putback.cfm" would be picked up and dumped into that spot in the program.
Close, but includes are placed and processed at runtime only. You are not reaching that point because of an expression error (by the CFML parser).
it is not recognizing that the end tag cfloop goes with with beginning cfloop in putback.cfm
The parser runs through your .cfm templates to build the AST before executing any code (runtime). The loop is never closed according to the parser because the include, which is another .cfm template, is inspected separately and never touched in its included state(s).
The Fix
<!--- stuff which is different in each program ---> is the part that should be included instead. However, this kind of coding practice is considered bad and eventually leads to Spaghetti code as you require, reuse and depend on variables inside of the loop. Your include should not be aware of its surroundings. If you absolutely have to do it this way, at least use cfmodule to pass variables to your include.
The proper way of solving this problem is by using an interface. You specify what you need, provide what you have and let <!--- stuff which is different in each program ---> serve this interface. This code structure would be based on cfcomponent and its cffunctions, implementing cfinterface.

Related

Append to JSON array within an JSON array ColdFusion

This is a follow up question to: Append to JSON array with ColdFusion, taking Null values into consideration?
That question was answered yesterday and worked perfectly (Thank you Kevin B. and Leigh!). However, the application I am pulling my JSON data from threw me a curve ball this morning. Sometimes, depending on the data I am requesting, it returns the entire JSON as an array like this:
[
{
"loginHosts": [
"server1.example.com"
],
"sudoHosts": [
"server1.example.com"
],
"CPG": [
"my_group"
],
"mail": "myuser#example.com",
"loginShell": "/bin/bash"
}
]
I don't know why that application does this. If I knew this was a possibility I would have added that information to my previous question, my apologies.
My attempts to find a solution lead me here first: Using JSON Data with Coldfusion . Looping over the JSON array as a collection seemed to work, but only if none of the array values were Null. I thought using this code, as in the previous question, would work if I used it for all the JSON fields:
<cfif NOT structKeyExists(myStruct, 'sudoHosts') OR NOT isArray(myStruct.sudoHosts)>
<cfset myStruct.sudoHosts = []>
</cfif>
This was not the case. I continually get:
Error: Can't cast Complex Object Type Array to String
Looking through the debug output, Lucee did throw this out: string Use Built-In-Function "serialize(Array):String" to create a String from Array. I did more digging and found this article: Railo tip: store complex data by using serialize(data). Sadly, Null values have struck again. Also, my understanding is serialize() is similar to evaluate(), and not recommended.
I will continue looking for a solution but any help is, as always, greatly appreciated!
-- EDIT --
I came across this thread: ColdFusion JSON object vs array of objects. I noticed the JSON in the question is an ARRAY [], and I applied the answer to my code, but am still running into the Null problem. I guess I don't know how to check for nested Null values. :(
Take it one step at a time.
Ideally you should determine why the response differs. Since you say those differences usually correspond to something different in your request, that strongly suggests you may be overlooking (or possibly misunderstanding) something in the remote API. I would recommend re-reviewing the API to identify that "something", in order to figure out the right approach. Otherwise, the code will quickly become unmanageable and inefficient as you continue to tweak it to handle each "new" situation.
If for some reason the API truly is returning different results without a valid reason, the best you can do is to code according to what you expect and fail gracefully when you receive something else. Start by listing the expected possibilities:
Response is a single structure containing certain keys OR
Response is an Array of structures containing certain keys
Based on the above, you can use the IsArray and IsStruct functions to determine the format of the response, and handle it accordingly. First examine the deserialized object. If it is an array, extract the structure in the first element (Note, I am assuming the array only contains a single element, as in the example. If it can contain multiple elements, you will need additional handling).
<cfset data = deserializeJson(originalJSON)>
....
<!--- Extract structure from first element of array --->
<cfif IsArray(data) && arrayLen(data)>
<cfset data = data[1]>
</cfif>
Next verify you are now working with a structure, containing the expected key(s). If so, go ahead with your usual processing. Otherwise, something unexpected happened and the code should perform the appropriate error handling.
<!--- Verify object is a structure and contains expected key(s) --->
<cfif IsStruct(data) && structKeyExists(data, "loginHosts")>
... process data as usual
<cfelse>
... data is not in expected format, do error handling here
</cfif>
The above is a very quick and dirty example, but should demonstrate the basic idea. As long as you are certain you are using the API correctly, all you can do is code for the expected and fail gracefully when something different happens.

ColdFusion loop of structures containing array in deserialized json

Here is Google calendar data retrieved from https://www.googleapis.com/calendar/v3/users/me/calendarList.
The response is in JSON, so I used the ColdFusion method deserializeJson to turn it into a CFML structure.
I cannot figure out the syntax to loop over this data. You'll see that within the CFML struct, 'items' is an array of calendars returned from Google, and every attempt to access the array within the struct generates a Java string conversion error or a syntax error, likely because I can't get the syntax correct.
Any help is very appreciated, thanks very much
Some trial and error will help - you are already on your way. The root object you dumped out already but we'll do it here to represent the object you dumped out as "obj":
<cfset obj = deserializejson(googleCal)>
The first level is a struct so you would address them as follows:
#obj.etag# // this is a string
items contains an array. So you have items[1-n] ... however many are in the array. This code would set myArrayObj as an array with 3 items (based on the dump above).
<cfset myArrayObj = obj.items>
You can verify using isArray:
#isArray(myArrayObj)#
Each array member contains a struct in turn so you can output:
#myArrayObj[1].accessRole# // this would be a string
... And so on. Make a note that index item 3 in the array is a blank struct so you need to "check" to see if the struct is empty before you work with it's keys. Investigate "structKeyExists()" for that purpose.
If you want to deal with each of the "items" in a loop (a pretty typical choice) you would simply do a cfscript loop or cfloop using array as in:
<cfloop array="#myArrayObj#" index="i">
<cfif structKeyExists(myArrayOb[i], "accessRole")>
#myArrayObj[i].accessRole#
</cfif>
</cfloop>
Hope this helps. Good luck!

coldfusion loop over file not working quite right

In ColdFusion I am creating and saving a file, then later looping over characters in the file to display part of it. This is almost working, but the loop is sometimes inserting characters that are formatting rather than just the output. And sometimes it is losing the formatting. Here are the original and the version as read:
The code:
<cfset colvalue = getPageContext().getRequest().getParameterValues('#col#')>
<cfset repa = colvalue[1]>
<cfloop file="#reppath#moxrep/#repa#.cfm" index="chunk" characters="500">
<cfoutput>#chunk#</cfoutput><br>
</cfloop>
Am I doing something wrong in the code? Is there a bug in the ColdFusion loop over file? And if so, is there a workaround?
<cfloop .. characters="500">
It is because your loop uses the "characters" attribute, which limits the number of characters "..read during each iteration of the loop..". That would be fine for a text file. However, since the file content is HTML, it breaks when you try and insert the <br> at an arbitrary position. That causes part of the HTML code to be displayed instead of rendered. For example:
<div <br> style="text-align: left; ">This will not render correctly</div>
That said, it begs the question why read the content line by line instead of just displaying the whole file?
Update:
You really cannot parse HTML with basic string functions or regular expressions - not with any reliability. Encountering a new line character does not necessarily mean you have reached the end of a particular block of HTML code. It is perfectly valid for an HTML element to span multiple lines. Plus, HTML elements are frequently nested. So it is near impossible to identify the "logical" endpoints using string functions (which is basically what the cfloop is doing) alone.
Instead, I would recommend using a tool like JSOUP which is specifically designed for parsing HTML. Once you have parsed the document, it is very easy to access specific elements or sections of the HTML.

SIMULINK Holding Previous Value of a Signal

I am trying to implement a pulse generator in SIMULINK that needs to know the previous 2 input values i.e. I need to know the previous 2 state values for the input signal. Also, I need to know the previous output value.
My pseudo code is:
IF !input AND input_prevValue AND !input_prevValue2
output = !output_pv
ELSE
output = output_pv;
I know that I can use legacy function importer and use C code to do this job in SIMULINK. However, the problem arises when you apply a configuration reference set to your model. The key problem is the flexibility. When you use this model somewhere else (say share it with a colleague or whoever), unless you have used a configuration reference set, you can rebuild the code (i.e. from S-Function Block) and run your model. But you cannot rebuild the code if the configuration reference set is applied.
My solution would be to implement the logic in a way that I can do the same without C functions. I tried to use the memory block in SIMULINK but apparently it doesn't do it. Does anyone know how to hold previous values for input and output in SIMULINK (for as long as the model is open)?
Have you tried with a MATLAB Function block? Alternatively, if you have a Stateflow license, this would lend itself nicely to a state chart.
EDIT
Based on your pseudo-code, I would expect the code in the MATLAB Function block to look like this
function op = logic_fcn(ip,ip_prev,ip_prev2,op_prev)
% #codegen
if ~ip && ip_prev && ~ip_prev2
op = ~op_prev;
else
op = op_prev;
end
where ip, ip_prev, ip_prev2 and op_prev are defined as boolean inputs and op as a boolean output. If you are using a fixed-step discrete solver, the memory block should work so that you would for example feed the output of the MATLAB Function block to a memory block (with the correct sample time), and the output of the memory block to the op_prev input of the MATLAB Function block.
You could (and should) test your function in MATLAB first (and/or a test Simulink model) to make sure it works and produces the output you expect for a given input.
This is reasonably straight forward to do with fundamental blocks,
Note that for the Switch block the "Criteria for passing first input:" has been changed to "u2~=0".

changing variables in loop in Jmeter

I have web request like this
Loop Controller(3)
moreSamples=true
startIndex=0
While Controller(${__javaScript(${moreSamples}==true)})
SOAP/XML-RPC Request(index=${startIndex})
Regular Expression Extractor(startIndex=newIndex,moreSamples=samples)
Now problem is I am not able to initialize moreSamples and startIndex in loop.
I tried two options:
Make moreSamples and startIndex as user defined variables. Now I am able to change their values using Regular Expression Extractor but not able to reinitialize them in outer loop using BeanShell PostProcessor like this:
vars.put("moreSamples","false")
vars.put("startIndex","0")
Make moreSamples and startIndex as User Parameters in preprocessor of of while loop but then I am not able to assign them values using Regular Expression Extractor.
Please suggest the mistakes or some new construct which can fit in.
Screenshot:
#bpsingh,
Can you do following things:
Add UserDefinedVariables on top of your Test Plan with two defined variables:
moreSamples, startIndex (like #ant suggested already)
Under the Download - PersistentSyncScope Sampler, you have two regular expression extractors in which I assume you want to extract some values and place it in these two variables from the above. Add BeanShellPostProcessor under the Download - PersistentSyncScope Sampler.
In BeanShellPostProcessor add following code:
vars.put("moreSamples","${REGEX_EXTRACT1}");
vars.put("startIndex","${REGEX_EXTRACT2}");
These two (moreSamples, startIndex) are global variables and changes on them should be visible outside of the loop.
Do you have to initialize them from the loop? How about adding those to User Defined Variables?
Or you can do it from your loop as well, the reason why it doesn't work for you is either the fact that you forgot to put the semi-colon ; after your expression(s) :
vars.put("moreSamples","false"); // ; <- was missing
vars.put("startIndex","0"); // ; <- was missing
I used BSF Sampler and it worked for me (don't forget to choose the language -> beanshell if you use this one). Here is my debug sampler (relevant part) :
START.HMS=101818
START.MS=1341821898080
START.YMD=20120709
TESTSTART.MS=1341822195274
moreSamples=false
startIndex=0
Update:
You need not to use both BSF Sampler and user defined variables. You can use either, and I see you have more user defined variables, no need for that. Have one of those at the start of your test. I'm still not clear what your problem is and what you're trying to achieve.
Actually problem here is I am using 2 loops and all answers don't take this properly into account.
Since pre/post processors are applied only to samplers not to loops there is no way to reinitialize the variables before while loop. Thus if I add initialize statements in preprocessor, loop run infinitely and if in postprocessor, it never executes. Only way to initialize is adding BSF sampler before while loop but that will spoil the reports as this sampler will also be recorded by listeners.
So only solution I found is run Download - PersistentSyncScope Sampler once and add BSF preprocessor with following scripts
vars.put("moreSamples","false");
vars.put("startIndex","0");
Now add while loop and add Download - PersistentSyncScope Sampler as its child.
That is the only solution till now. Thanks everyone to help me understand the problem.

Resources