Splitting a Comma-Separated List using Movable Type Template Tags

| 8 Comments | No TrackBacks |
I noticed this forum question today: "Split Modifier for Template Tags?". A 'Sunset Bill' wanted to know if there was an easy or built-in way in Movable Type's templating language to split the comma-separated contents of a custom field into multiple parts that could be easily looped over.  He was wondering if a 'split' modifier might exist or if someone had already created one using a plugin.
As far as I know, no such plugin or modifier currently exists, but I did start wondering about this particular problem, having run into it myself on occasion too.  I usuallly solved it by just using more custom fields, but I believe I found a 'real' solution tonight.  Here is some example code:

<mt:var name="thelist" value="foo,bar,bla,baz">

<mt:setvarblock name="separator">
</foobar:setvarblock>
<foobar:setvarblock name="thearray" function="push">
</mt:setvarblock>

<mt:setvarblock name="theexpression">
<foobar:setvarblock name="thearray" function="push">
<mt:var name="thelist" regex_replace="/,/gsi","$separator">
</foobar:setvarblock>
</mt:setvarblock>

<mt:var name="theexpression" regex_replace="/foobar/gsi","mt" mteval="1">

<mt:loop name="thearray">
<li><mt:var name="__value__"></li>
</mt:loop>

So maybe this deserves a little explanation...

The first line is easy: just set up a variable containing the comma-separated list of items.

The second line sets up a utility variable called 'separator', which contains some tags that almost look like MT tags except they have 'foobar' instead of 'mt' in their name.  This is to stop MT's templating engine from already trying to interpret these tags here, which would lead to an error later on.

The third line is where the magic happens: the regex_replace modifier is used to replace the commas in the list with the separator that was defined in the previous line, and opening+closing tags are added before and after the result, which is stored in a variable called 'theexpression'.

Line four also has quite some magic in it: regex_replace is used once more to turn the fake MT tags into real ones by replacing 'foobar' with 'mt', then the entire result is evaluated as if it was MT template code by the mteval modifier.  The result is that each of the items of the original list gets pushed onto the array 'thearray'.

The last part of the code simply loops over the array and displays each value in turn, which gives this result:

  • foo
  • bar
  • bla
  • baz

  • No TrackBacks

    TrackBack URL: https://www.movabletips.com/cgi-bin/mt/mt-tb.cgi/42

    8 Comments

    I can hardly believe my incredibly good fortune here!! Yesterday, I was looking for a way to achieve in movable type the equivalent of a split in programming languages and *BOOM* within hours you have posted the solution. And this is one of the more clever pieces of programming code I've ever seen. Mucho kudos.

    The reason? I desperately wanted the split? Well, I want to display an EntryBody and use both the words="n" attribute as well as convert_breaks="0" attribute. Namely: show the first n words of the entry *BUT* preserve the line-breaks. Well, I tried all combinations I could think of, but no luck. The only discussion I found of this was someone back in '04 reporting the exact same problem.

    I came up with a workable solution which was 10% MT and 90% JS. In seeking whether I could improve on it,I stumbled on the MT regex_replace with which I was previously unfamiliar, and so I wondered whether it could be done in MT. So I started translating my solution line by line from JS to MT. The missing link was the split I had done in JS, and your gravity-defying solution was the last piece of the puzzle.

    So, without any further ado (and with apologies for the lengthy ado thus far), here is the MT module Words_And_BRreaks, my solution for displaying the first n words of an entry, AND preserving the line-breaks:

    ------------------------------------------------------------------------------------------------------------------------------------------
    MODULE BEGINS HERE
    ------------------------------------------------------------------------------------------------------------------------------------------


    <MTSetVarBlock name="myBody"><MTGetVar name="param_body"></MTSetVarBlock>

    <MTIgnore> 1. ENSURE LINE-BREAKS WON'T MESS UP OUR REGEXP'S </MTIgnore>

    <MTSetVarBlock name="myBody"><MTGetVar name="myBody" regex_replace="/[\t\r\n]/gi"," "$></MTSetVarBlock>

    <MTIgnore> 2. WE WILL NEED TO RESTORE P'S AND BR'S </MTIgnore>

    <MTSetVarBlock name="myBody"><MTGetVar name="myBody" regex_replace="/<br\s*(\/)?\s*>/gi","brbrb"$></MTSetVarBlock>
    <MTSetVarBlock name="myBody"><MTGetVar name="myBody" regex_replace="/<p>/gi","popop"$></MTSetVarBlock>
    <MTSetVarBlock name="myBody"><MTGetVar name="myBody" regex_replace="/<\/p>/gi","pcpcp"$></MTSetVarBlock>

    <MTIgnore> 3. NOW GET RID OF THE HTML -- I THINK THIS RELIES ON FACT THAT (X|Y|Z) ARE EVALUATED LEFT > RIGHT </MTIgnore>

    <MTSetVarBlock name="myBody"><MTGetVar name="myBody" regex_replace="/(<script.*?<\/script>|<style.*?<\/style>|<!\-\-.*?\-\->|<.*?>)/gi",""$></MTSetVarBlock>

    <MTIgnore> 4. GET RID OF EXTRA SPACES BEFORE DOING WORK BASED ON THEM </MTIgnore>

    <MTSetVarBlock name="myBody"><MTGetVar name="myBody" regex_replace="/ +/gi"," "$></MTSetVarBlock>

    <MTIgnore>
    5. SPLIT THE STRING, ON THE SPACE CHARACTER, INTO AN ARRAY

    THIS BLOCK IS Maarten Schenk'S CODE: http://www.movabletips.com/2010/03/splitting-a-comma-separated-list-in-movable-type-using-template-tags.html

    I'VE GOTTEN RID OF THE LINE BREAKS WITHIN IT, SO THAT EXTRA WHITE SPACE DOESN'T INTERFERE WITH DESIRED WORD COUNT
    </MTIgnore>

    <mt:setvarblock name="separator"></foobar:setvarblock><foobar:setvarblock name="thearray" function="push"></mt:setvarblock>

    <mt:setvarblock name="theexpression"><foobar:setvarblock name="thearray" function="push"><mt:var name="myBody" regex_replace="/ /gsi","$separator"></foobar:setvarblock></mt:setvarblock>
    <mt:var name="theexpression" regex_replace="/foobar/gsi","mt" mteval="1">

    <MTIgnore> 6. PREPARE FOR RE-JOINING: ENSURE WE WILL END UP WITH AT MOST N ELEMENTS </MTIgnore>

    <MTSetVarBlock name="my_count"><MTGetVar name="count(thearray)"></MTSetVarBlock>
    <MTIf name="my_count" gt="$param_words"><MTSetVar name="my_count" value="$param_words"></MTIf>
    <MTSetVar name="my_count" op="sub" value="1">

    <MTIgnore> 7. NOW GENERATE SECOND ARRAY WHICH IS FIRST 100 ELEMENTS OF FIRST </MTIgnore>

    <MTFor from="0" to="$my_count" step="1"><MTSetVarBlock name="new_element"><MTGetVar name="thearray" index="$__index__"></MTSetVarBlock><MTSetVar name="thearray2" function="push" value="$new_element"></MTFor>

    <MTIgnore> 8. NOW RE-JOIN SECOND ARRAY, SO WE HAVE SPLICED IT, AND EFFECTIVELY ACCOMPLISHED WORDS= </MTIgnore>

    <MTSetVarBlock name="myBody"><MTLoop name="thearray2" glue=" "><MTVar name="__value__"></MTLoop></MTSetVarBlock>

    <MTIgnore> 9. RESTORE THE LINE BREAKS </MTIgnore>

    <MTSetVarBlock name="myBody"><MTGetVar name="myBody" regex_replace="/brbrb/gi","<br/>"$></MTSetVarBlock>
    <MTSetVarBlock name="myBody"><MTGetVar name="myBody" regex_replace="/popop/gi","<p>"$></MTSetVarBlock>
    <MTSetVarBlock name="myBody"><MTGetVar name="myBody" regex_replace="/pcpcp/gi","</p>"$></MTSetVarBlock>

    <MTGetVar name="myBody">...

    ------------------------------------------------------------------------------------------------------------------------------------------
    MODULE ENDS HERE
    ------------------------------------------------------------------------------------------------------------------------------------------

    Use the module thusly:

    <MTEntries lastn="1">
    <MTSetVarBlock name="param_body"><MTEntryBody></MTSetVarBlock>
    <MTinclude module="Words_And_Breaks" param_body="$param_body" param_words="100">
    </MTEntries>

    Please note:

    1. The module leaves in any initial <p>, so you'll have to get rid of that too if you want it gone.
    2. The module preserves only br's and p's. If your html has line-breaks because of any other tags, such as div's, you'll have to modify the code.
    3. The module tested successfully on a fairly robust piece of html: tons of js, css, attributes, line-breaks, the whole 9-yards.

    Et voila! I'm relatively new to MT programming, so I'd love some feedback on this.

    And you, Maarten Schenk, are a scholar and a gentleman!

    Here's another way to split a string with the RegexList plugin :

    <$mt:var name="thestring" value="FOO,bar,bLA,Baz"$>
    <$mt:Var name="thestring" regex_list="/(.+)/","$1","/([^,]+)/" setvar="thelist"$>
    
    • FOO
    • bar
    • bLA
    • Baz

    Additionally, if you want to clean up the capitalization:

    <$mt:Var name="thestring" regex_list="/(.)(.+)/","\u$1\L$2\E","/([^,]+)/" setvar="thelist"$ >
    
    • Foo
    • Bar
    • Bla
    • Baz

    This use case is explained in detail on the plugin github documentation.

    What a information of un-ambiguity and preserveness of precious experience regarding unpredicted emotions.

    I am sure this paragraph has touched all the internet viewers, its really really pleasant post on building up new weblog.

    Great delivery. Solid arguments. Keep up the amazing effort.

    Someone necessarily help to make seriously posts I would
    state. That is the first time I frequented your web page and up to now?
    I surprised with the research you made to make this particular publish
    amazing. Excellent process!

    Quality articles is the key to be a focus for the people to pay a visit the site, that's what this site is providing.

    It's an amazing post in favor of all the internet people; they will
    get benefit from it I am sure.

    Leave a comment


    Movable Type Help?

    "Can my Movable Type issue or project be taken care of by a professional?" Yes It Can Be! Contact YesItCan.be
    Powered by Movable Type 5.2.7