Copy link to clipboard
Copied
I've only recently gotten into XML and XPath (loving it) but I'm stumped as to how I can determine if I'm at the end of a <cfloop> that is based on an array returned from an XPath. Here's my code
<cfloop array="#xmlSearch( application.config, '/environment/app/meta_data/meta_tags/tag[@name]' )#" index="i">
<cfset i = xmlParse( i )>
<cfoutput><meta name="#i.tag.xmlAttributes[ 'name' ]#" content="#i.tag.xmlAttributes[ 'content' ]#"></cfoutput>
<!--- How can I tell if I'm on the last iteration of this loop? --->
</cfloop>
Copy link to clipboard
Copied
Set a variable to 1 before you start your loop. Increment it as the first command in your loop. Check to see if it's the same as the length of your array.
Copy link to clipboard
Copied
I recomment not using that array-looping construct if you need to know which element you're at (eg: the first one, the fifth one, the last one), as CF - foolishly - does not expose this to you. Plus Adobe incorrectly used "index" to refer to the array element.
Just use a normal for() loop:
for (i=1; i <= arrayLen(a); i++){
// stuff goes here
}
Or the tag equivalent:
<cfloop index="i" from="1" to="#arrayLen(a)#">
<!--- stuff goes here --->
</cfloop>
--
Adam
Copy link to clipboard
Copied
So, staying with a completely numeric loop, I would have to do additional steps of setting information. There's nothing more optimized than that?
<cfloop from="1" to="#arrayLen( xmlSearch( application.config, 'environment/app/meta_data/meta_tags/tag[@name]' )#" index="j">
...
</cfloop>
Well, this raises a different question. In my xmlSearch() function, you can see that I only want 'tag' elements that have a 'name' attribute. So if my loop counter starts at 1, this isn't necessarily the same index I could use to just specify it as an xmlChild such as:
application.config[ 'environment' ][ 'app' ][ 'meta_data' ][ 'meta_tags' ].xmlChildren[ j ].xmlAttributes[ 'name' ]
So how would I stick with a numeric loop (which I could easily determine if I'm at the end of), but also get the appropriate index?
The only way I could think of (and it would again require additional coding) is to loop through ALL tags, and then perform additional internal conditional checking to see if the current node has a 'name' attribute.
Copy link to clipboard
Copied
OK, here's what I came up with:
<cfloop from="1" to="#arrayLen( xmlSearch( application.config, '/environment/app/meta_data/meta_tags/tag' ) )#" index="j">
<cfset k = application.config[ 'environment' ][ 'app' ][ 'meta_data' ][ 'meta_tags' ].xmlChildren[ j ]>
<cfset k = xmlParse( k )>
<cfif structKeyExists( k.tag.xmlAttributes, 'name' )>
<cfoutput><meta name="#k.tag.xmlAttributes[ 'name' ]#" content="#k.tag.xmlAttributes[ 'content' ]#"><cfif j lt arrayLen( xmlSearch( application.config, '/environment/app/meta_data/meta_tags/tag' ) )>#chr( 10 )##repeatString( chr( 9 ), 2 )#</cfif></cfoutput>
</cfif>
</cfloop>
Copy link to clipboard
Copied
You put your xmlSearch() result into a variable, then loop over the variable. That way you get to both use the variable as the loop control and access it in the loop:
a = xmlSearch(stuff);
for (i=1; i <= arrayLen(a); i++){
thisElement = a;
// etc
}
--
Adam