Skip to main content
aashan77
Participant
February 1, 2026
Question

Extract First Menu Category from XML String in ColdFusion

  • February 1, 2026
  • 3 replies
  • 50 views

Hi everyone,

I’m working with an XML feed in a ColdFusion project where menu-related data is stored as a comma-separated string inside a single node. Each entry starts with a category or brand name, followed by multiple items, but I only need to display that first value.

Example XML (simplified):

<cfxml variable="menuData">
<catalog>
  <item>
    <type>Drinks</type>
    <details>Cold Brew Coffee, Vanilla Latte, Caramel Mocha, Iced Americano</details>
  </item>
  <item>
    <type>Specials</type>
    <details>Holiday Drinks, Peppermint Mocha, Sugar Cookie Latte</details>
  </item>
</catalog>
</cfxml>

What I’m trying to output is just the first part of each details string:

Cold Brew Coffee
Holiday Drinks

I assume this can be handled with string functions after parsing the XML, but I’d like to confirm the cleanest approach in ColdFusion, especially if the data grows later.

This is part of a menu-structuring project where accurate category display matters, similar to how café drink menus are organized on sites like https://dbrosmenu.com/.

Any guidance or example code would be appreciated. Thanks!

    3 replies

    BKBK
    Community Expert
    Community Expert
    February 3, 2026

    Hi ​@aashan77 , As you have not yet responded, here then are two more solutions, both emphasizing code reuse:

    cfscript>
    /*
    * Extracts details lists from catalog XML
    * @xmlDoc: XML object
    * @returns: array of structs: [{type="", details=[]}]
    */
    function extractItemDetails(required xml xmlDoc) {
    var items = xmlSearch(xmlDoc, "/catalog/item");
    var results = [];

    for (var item in items) {
    arrayAppend(results, {
    type : item.type.xmlText,
    details : listToArray(item.details.xmlText, ",")
    });
    }

    return results;
    }
    </cfscript>

    <cfset itemDetails = extractItemDetails(menuData)>

    <!---<cfdump var="#itemDetails#">--->

    <cfoutput>
    <p>
    itemDetails[1].details[1]: #itemDetails[1].details[1]# <br>
    itemDetails[1].details[2]: #itemDetails[1].details[2]# <br>
    itemDetails[1].details[3]: #itemDetails[1].details[3]# <br>
    <p>
    itemDetails[2].details[1]: #itemDetails[2].details[1]# <br>
    itemDetails[2].details[2]: #itemDetails[2].details[2]# <br>
    itemDetails[2].details[3]: #itemDetails[2].details[3]# <br>
    </cfoutput>
    <cfscript>
    function extractDetailsLists(required xml xmlDoc) {
    /*
    Suppose you want to access the 'details' and nothing else.
    Then you can just use the Xpath to extract the 'details'
    */
    var nodes = xmlSearch(xmlDoc, "//details");
    var results = [];

    for (var node in nodes) {
    arrayAppend(results, listToArray(node.xmlText, ","));
    }

    return results;
    }
    </cfscript>

    <cfset detailsLists = extractDetailsLists(menuData)>

    <!---<cfdump var="#detailsLists#">--->

    <cfoutput>
    <p>
    detailsLists[1][1]: #detailsLists[1][1]# <br>
    detailsLists[1][2]: #detailsLists[1][2]# <br>
    detailsLists[1][3]: #detailsLists[1][3]# <br>
    <p>
    detailsLists[2][1]: #detailsLists[2][1]# <br>
    detailsLists[2][2]: #detailsLists[2][2]# <br>
    detailsLists[2][3]: #detailsLists[2][3]# <br>
    </cfoutput>

     

    Charlie Arehart
    Community Expert
    Community Expert
    February 1, 2026

    Here's a different take (to put in after your closing cfxml tag):

    <cfset data="#menudata.catalog#">

    <cfloop array="#data.item#" index="menuitem" >
      <cfoutput>#menuitem.type.xmltext#:
    #listfirst(menuitem.details.xmltext)#<p></cfoutput>
    </cfloop>

    This shows how easily you can leverage how cf internally represents such an xml chunk (pulled in that way or via cf's xmlparse function) as an array already. My code then uses cf's listfirst function, which is perfect for your current need. It's sweet how all this can be done in just a few lines. 

     

    BTW, while the cf docs have some discussion of this power of cf xml handling, the best still is a 30-page intro from Nate Weiss done over 20 years ago yet still valuable. I keep that  copy of the pdf (long gone from Adobe's site) on my site.

     

    It also discusses xmlsearch as bkbk mentioned. All great tools for you who are working with xml in cf. 

    /Charlie (troubleshooter, carehart. org)
    BKBK
    Community Expert
    Community Expert
    February 1, 2026

    If the data XML is going to grow later, then best-practice is that you reuse code, hence that you implement a function. The function could use XmlSearch, for example, to find the ‘details’ lists. 

     

    It is then straightforward to combine items from the different lists, in any order you want. A code sample follows.

    <cfxml variable="menuData">
    <catalog>
      <item>
        <type>Drinks</type>
        <details>Cold Brew Coffee, Vanilla Latte, Caramel Mocha, Iced Americano</details>
      </item>
      <item>
        <type>Specials</type>
        <details>Holiday Drinks, Peppermint Mocha, Sugar Cookie Latte</details>
      </item>
    </catalog>
    </cfxml>

    <!--- The function returns an array consisting of the 'details' lists --->
    <cfset arrayOfDetailsLists = getDetailsListsArray(menuData)>

    <!---<cfdump var="#arrayOfDetailsLists#">--->
    <cfoutput>
        First item on first details list: #listGetAt(arrayOfDetailsLists[1],1)# <br>
        First item on second details list: #listGetAt(arrayOfDetailsLists[2],1)# <br>
        Second item on first details list: #listGetAt(arrayOfDetailsLists[1],2)# <br>
        Second item on second details list: #listGetAt(arrayOfDetailsLists[2],2)# <br>
        etcetera    
    </cfoutput>

    <cffunction name="getDetailsListsArray" output="false" returntype="Array">
        <cfargument name="menuDataXml" required="true" type="xml">
        
        <!--- 
        Search the XML object and extract the 'details' lists.
        Assumption: the structure catalog/item/details remains fixed in the menuData XML.
        --->
        <cfset var detailsArray = xmlSearch(arguments.menuDataXml, "catalog/item/details")> 
        
        <!--- Initialize --->
        <cfset var detailsListsArray = []>
        <cfset var i = 1>


         <!--- Store each ‘details’ list as an array item --->
        <cfloop array="#detailsArray#" item="detailsList">
            <cfset detailsListsArray[i] = detailsList.xmlText>
            <cfset i = i+1>
        </cfloop>
        
        <cfreturn detailsListsArray>    
    </cffunction>