Coldfusion - Check if XmlNode exists

3.1k Views Asked by At

I've really been struggling to find a solution to this. My code is different from what I've seen on a Google search, and nothing I've tried will work. Basically as the title suggests I want to check if an Xml Node exists. This is because of erratic XML returned from a YouTube feed. Code is below.

<cfset YouTubeXml = xmlParse(#YouTubeFavourites.FileContent#) />
<cfset group = XmlSearch(YouTubeXml, "//media:group") />    

<cfloop from="1" to="25" index="i">
    <cfoutput>
        #group[i]['media:thumbnail'][i]['url']#
    </cfoutput>
</cfloop>

Basically the error says that #group[i]['media:thumbnail'][i]['url']# doesn't exist. Hope someone can help.

4

There are 4 best solutions below

4
On

The below code will check to ensure the variable exists before it tries to display it. The nested approach is the only way to ensure each piece exists as you go along. There are functions to make it look prettier, but that's a topic for another question.

<cfset YouTubeXml = xmlParse( YouTubeFavourites.FileContent ) />
<cfset group = XmlSearch( YouTubeXml, "//media:group" ) />

<cfoutput>
<cfloop from="1" to="25" index="i">
    <cfif StructKeyExists( Group, i )
        AND StructKeyExists( Group[ i ], 'media:thumbnail' )
        AND StructKeyExists( Group[ i ][ 'media:thumbnail' ], i )
        AND StructKeyExists( Group[ i ][ 'media:thumbnail' ][ i ], 'url' )>
        #group[i]['media:thumbnail'][i]['url']#
    </cfif>
</cfloop>
</cfoutput>

I find it odd that you're using i twice in the variable name, but I'm not familiar with the Youtube API, so maybe that is correct.

I've changed two things in your code that weren't need. I removed the extra ## signs in xmlParse() as it's already going to be treated as a variable there. I also moved the <cfoutput> out of the loop, as there's a slight performance loss declaring <cfoutput> multiple times.

0
On

Try using isDefined() ?

<cfset YouTubeXml = xmlParse(YouTubeFavourites.FileContent) />
<cfset group = XmlSearch(YouTubeXml, "//media:group") />

<cfloop from="1" to="25" index="i">
<cfif isDefined("#group[i]['media:thumbnail'][i]['url']#")>
    <cfoutput>
        #group[i]['media:thumbnail'][i]['url']#
    </cfoutput>
</cfif>
</cfloop>
0
On

A year on and I've finally found the answer to this. It will be useful for others. I've got the final working code below.

<cfhttp url="https://gdata.youtube.com/feeds/api/users/Shuggy23/favorites" method="get" result="YouTube">   
            </cfhttp>
            <cfset xml = xmlParse(#YouTube.FileContent#) />

            <cfset media = XmlSearch(xml, "//media:group/") />
            <cfloop index="i" from="1" to="8">
                <cfoutput>
                    #media[i]['media:thumbnail'].XmlAttributes['url']# <br />
                </cfoutput>
            </cfloop>

Cheers,

Douglas

0
On

Okay, some things are mixed up here. First of all, the xmlSearch function always returns an array, so using the structKeyExists function on it as suggested will naturally throw an exception. Second thing to consider is: Does the source XML contain namespaces? If so, you need to tell your XPath term "//:media:group" (this is an odd implementation by ColdFusion itself).

<cfset group = xmlSearch(YouTubeXml, "//:media:group")>
<cfif not arrayIsEmpty(group)>

    <cfloop array="#group#" index="xmlNode">
        <cfif structKeyExists(xmlNode, "url")>
            <cfoutput>#xmlNode.url.xmlText#</cfoutput>
        </cfif>
    </cfloop>

<cfelse>
    <cfoutput>The XML does not contain the desired nodes.</cfoutput>
</cfif>

However, your exmaple code seems to assume another array within the node you are searching for by XPath. If you need to access further nodes in the inner XML of your resulted node, you either need to modify your XPath term to get the children nodes beforehand or you do another XPath search on the resulted node in the loop. ColdFusion does not assign child nodes automatically to its parent as arrays.

If this doesn't work for you, please post an example of the XML.