Skip to main content
Inspiring
August 24, 2012
Question

How can I tell I'm at the end of an array loop based on XPath?

  • August 24, 2012
  • 3 replies
  • 1061 views

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>

    This topic has been closed for replies.

    3 replies

    Inspiring
    August 25, 2012

    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.

    Inspiring
    August 25, 2012

    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>

    Inspiring
    August 25, 2012

    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

    Inspiring
    August 25, 2012

    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.