Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
0

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

Enthusiast ,
Aug 24, 2012 Aug 24, 2012

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>

963
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Aug 25, 2012 Aug 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.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Aug 25, 2012 Aug 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

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Aug 25, 2012 Aug 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.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Aug 25, 2012 Aug 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>

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Aug 25, 2012 Aug 25, 2012
LATEST

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

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Resources