3 Replies - 1161 Views - Last Post: 01 April 2011 - 11:54 AM Rate Topic: -----

#1 SleepingInChapel  Icon User is offline

  • D.I.C Head

Reputation: 5
  • View blog
  • Posts: 59
  • Joined: 02-January 09

Fun with Recursion

Posted 31 March 2011 - 02:01 PM

Hey guys... I've got a fun one...

What I'm trying to do is read an XML file, then output a taxonomy or categorization path. The taxonomy is written in the XML file as a bunch of nested nodes, so it's pretty obvious that this is going to require some kind of recursion.

The XML file looks kind of like this:
<cfxml variable="xmlBulletin">
    <bulletin>
        <contents>
            ...
        </contents>
        <taxonomy>
            <category1>
                <subcategory1>
                    <subcategory2>
                        true
                    </subcategory2>
                    <subcategory3>
                        <subcategory4>
                            true
                        </subcategory4>
                    </subcategory3>
                </subcategory1>
            </category1>
        </taxonomy>
    </bulletin>
</cfxml>



This basically means that my outputted taxonomy paths should be:
/taxonomy/category1/subcategory1/subcategory2
/taxonomy/category1/subcategory1/subcategory3/subcategory4

Now, I've attempted to write a function to output those paths in the above format, but I need a little help. Currently, my function only works for one path. I've tried to modify it to handle the whole tree, but I run into problems when siblings are introduced. For example, having subcategory2 and subcategory3 both part of subcategory1...

<cfset taxPathVar = ""> <!--- Stored outside of the function's scope --->
<cffunction name="getFullTaxonomyPath" returntype="string">
    <cfargument name="inXML" type="xml" required="yes">
    <cfargument name="firstRun" type="boolean" required="yes" default=true>
	
    <cfif firstRun>
        <cfset taxPathVar = "">
    </cfif>
	
    <cfset taxPathVar = taxPathVar & "/" & inXML.XmlName>
	
    <cfif ArrayLen(inXML.xmlChildren)>
        <cfset myvar = getFullTaxonomyPath(inXML=inXML.xmlChildren[1], firstRun=false)>
    </cfif>

    <cfreturn taxPathVar>
</cffunction> 



Called with:

<cfoutput>#getFullTaxonomyPath(xmlBulletin.bulletin.taxonomy)#</cfoutput>



It currently only outputs one path:
/taxonomy/category1/subcategory1/subcategory2

I'm just having trouble wrapping my head around how to let my function keep track of where it's been in the tree...

Any kind of suggestion would be helpful... Can this even be done with one recursive function? Thanks.

Full Source

This post has been edited by SleepingInChapel: 31 March 2011 - 02:47 PM


Is This A Good Question/Topic? 0
  • +

Replies To: Fun with Recursion

#2 Craig328  Icon User is offline

  • I make this look good
  • member icon

Reputation: 1890
  • View blog
  • Posts: 3,429
  • Joined: 13-January 08

Re: Fun with Recursion

Posted 01 April 2011 - 06:45 AM

Wow. That's gonna be a bear.

First thought I had was maybe (understand I've not had to build something like this) you need to start with taking your XML and turning it into something easier to work with. My brain went "string" but then the smarter part of my brain went "check CFLib dummy and see if anyone else has run into this". So I did and I encountered this interesting function: flattenXmlToStruct.

Now, my understanding of what that does is it takes your XML and gives you back a struct which is much easier to loop over and deal with (IMO). You can deal with structKeys as levels of recursion...which should allow you drill down pretty easily I should think.

My other immediate thought regarding "string" went something like this: you take your XML, drop it into a string and then parse through the string looking for "<" (to indicate a beginning level) and "/>" (to indicate the end to a level). You'd build your taxonomy paths on the fly as the string would lay it out that way for you and all you'd need to do is keep count and match the beginning of levels to their ends...if you get what I mean. This idea though relies heavily upon the XML not having something that looks like this (actual example of something I'm working with:
<Confirmation Number="724DL5" PNR="X7S6LZ" />

Because that example there IS a new level and it has sublevels to it but because the vendor that sent me that decided to embed values into it as opposed to separate sublevels (and to make matters even more fun, they're not consistent with this) my string parsing suggestion would need to take such things into account.

It can be done but it'll be a cast iron bitch to keep straight as you code it.
Was This Post Helpful? 1
  • +
  • -

#3 SleepingInChapel  Icon User is offline

  • D.I.C Head

Reputation: 5
  • View blog
  • Posts: 59
  • Joined: 02-January 09

Re: Fun with Recursion

Posted 01 April 2011 - 11:47 AM

View PostCraig328, on 01 April 2011 - 08:45 AM, said:

First thought I had was maybe (understand I've not had to build something like this) you need to start with taking your XML and turning it into something easier to work with. My brain went "string" but then the smarter part of my brain went "check CFLib dummy and see if anyone else has run into this". So I did and I encountered this interesting function: flattenXmlToStruct.


Holy cow Craig, you have no idea how much easier you've made this on me! :lol:

Pretty much all I have to do now is:
<cfset myvar = flattenXmlToStruct(xmlBulletin.bulletin.taxonomy)>
<cfloop collection="#myvar#" item="key">
	<cfoutput>#key#: #myvar[key]#<br /></cfoutput>
</cfloop>



Thank you, thank you, thank you!
Was This Post Helpful? 0
  • +
  • -

#4 Craig328  Icon User is offline

  • I make this look good
  • member icon

Reputation: 1890
  • View blog
  • Posts: 3,429
  • Joined: 13-January 08

Re: Fun with Recursion

Posted 01 April 2011 - 11:54 AM

You know, in the midst of a week wherein I had my laptop crash with a bad drive (losing an assload of work) and then mere hours later rear-ended a guy on slick pavement (very minor accident, no damage...but still) to hear that helped made the end of the week a little better. Glad it did the trick for you.

All I can take credit for is knowing where to find cflib.org tho. What I really need is a bolt of inspiration to help me with my effort to build a Coldfusion, platform-agnostic, Twitter module. OAuth will end up being the death of me yet. :)
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1