问题
I am working to build a menu in coldfusion based on xml.
current working function:
<cffunction name="xmlNav" access="private" returntype="struct" output="false">
<cfargument name="qGetNav" type="query" required="true">
<cfscript>
var qNav=Arguments.qGetNav;
var xmlNav=StructNew();
var myXmlDoc=xmlNew();
var route='';
myXmlDoc.XMLRoot = XMLElemNew(myXmlDoc,"UL");
myXmlDoc.UL.xmlAttributes.ID="nav-main-links";
for(q=1;q<=qNav.recordCount;q++){
//setup li
myXmlDoc.UL.XmlChildren[q]=XmlElemNew(myXmlDoc,"LI");
myXmlDoc.UL.XmlChildren[q].xmlAttributes.ID="id" & qNav["navid"][q];
myXmlDoc.UL.XmlChildren[q].xmlAttributes.CLASS="standby";
//setup route
myXmlDoc.UL.XmlChildren[q].a=XmlElemNew(myXmlDoc,"A");
route=qNav["Route"][q];
if(qNav["Version"][q] Eq "CB"){
route="/?event=" & route;
}
else if(qNav["Version"][q] Eq "L"){
route="http://" & route;
}
myXmlDoc.UL.XmlChildren[q].A.xmlAttributes.HREF=route;
myXmlDoc.UL.XmlChildren[q].A.xmlAttributes.TARGET=qNav["LinkTarget"][q];
myXmlDoc.UL.XmlChildren[q].A.xmlAttributes.TITLE=qNav["LinkTitle"][q];
//setup route text
myXmlDoc.UL.XmlChildren[q].A.SPAN=XmlElemNew(myXmlDoc,"SPAN");
myXmlDoc.UL.XmlChildren[q].A.SPAN.xmlText=qNav["TextDesc"][q];
myXmlDoc.UL.XmlChildren[q].A.SPAN.FONT=XmlElemNew(myXmlDoc,"FONT");
myXmlDoc.UL.XmlChildren[q].A.SPAN.FONT.xmlAttributes.CLASS="menuItemType";
myXmlDoc.UL.XmlChildren[q].A.SPAN.FONT.xmlText="(" & qNav["Version"][q] & ")";
}
xmlNav.xmlNavString=toString(myXmlDoc);
xmlNav.xmlNavString=replaceNoCase(xmlNav.xmlNavString,">",CHR(62),"all");
xmlNav.xmlNavString=replaceNoCase(xmlNav.xmlNavString,"<",CHR(60),"all");
xmlNav.xmlNavString=replaceNoCase(xmlNav.xmlNavString,"&",CHR(38),"all");
xmlNav.xmlNav=myXmlDoc;
return xmlNav;
</cfscript>
</cffunction>
I need to account for children and I am running into some significant difficulty. Here is the example I am using based on arrays and structs:
<cffunction name="arrayNav" access="private" returntype="struct" output="false">
<cfargument name="qGetNav" type="query" required="true">
<cfscript>
var qNav=Arguments.qGetNav;
var arrayNav=StructNew();
var aNavTree = arrayNew(1);
var aNavMenuItems = arrayNew(1);
var sNavLookup = structNew();
for(q=1;q<=qNav.recordCount;q++){
sThis = structNew();
sThis.data = structNew();
sThis.data.navid = qNav["navid"][q];
sThis.data.Route = qNav["Route"][q];
sThis.data.Version = qNav["Version"][q];
if(qNav["Version"][q] Eq "CB"){
arrayAppend(aNavMenuItems,qNav["Route"][q]);
}
sThis.data.LinkTarget = qNav["LinkTarget"][q];
sThis.data.LinkTitle = qNav["LinkTitle"][q];
sThis.data.TextDesc = qNav["TextDesc"][q];
sThis.children = arrayNew(1);
/*
now loop through
avoid dupes from the levelid, this should prob be handled in the query above by only selecting
the right levels, or using a select distinct without the levelid in there
*/
if(Not structKeyExists(sNavLookup,qNav["navid"][q])){
sNavLookup[qNav["navid"][q]] = sThis;
}
else{
//do nothing
}
if(qNav["NavParentId"][q] EQ 0){
arrayAppend(aNavTree, sThis);
}
else{
if(structKeyExists(sNavLookup, qNav["NavParentId"][q])){
arrayAppend(sNavLookup[qNav["NavParentId"][q]].children, sThis);
}
else{
//parent not found
}
}
}
arrayNav.arrayNav=aNavTree;
arrayNav.arrayNavMenuItems=aNavMenuItems;
return arrayNav;
</cfscript>
</cffunction>
hoping to avoid recursion if I can. so my question is how can add a block to the for loop that searches the xml file for the parent node and adds children nodes to it. I am literally stuck on the search piece. so far I can find the node for example using xmlNav.findNode=XmlSearch(myXmlDoc,"/UL/LI[@ID='id57']");
to find the position, but having trouble inserting the item there.
回答1:
After a ton of effort and collaboration, I want to share this with everyone. The following 2 functions generate an xml menu based on a the following query. I truly hope this helps others in the geek community.
<cfquery name="qGetNav" datasource="pcmenusqldev">
select navid,navparentid,navorder,Route,Version,LinkTarget,LinkTitle,TextDesc
from rhNavRoutesByLevel,rhnavRoutes
where rhnavRoutes.ID=rhNavRoutesByLevel.NavID And LevelID = 1
order by navParentId, navOrder, navId
</cfquery>
<cfset aNav = buildNav(qgetNav)>
<cfdump var="#qgetNav#" label="qGetNav" expand="no">
<cfdump var="#buildNav(qGetNav)#" expand="no" label="buildNav">
<hr><hr><hr>
<cfset testme=structnew()>
<cfset testme.menu=buildListXML(aNav)>
<cfdump var="#testme#">
<hr><hr><hr>
<cfoutput>#buildListXML(aNav)#</cfoutput>
<hr><hr><hr>
<cfoutput>#buildList(aNav)#</cfoutput>
<cffunction name="buildNav" returntype="array">
<cfargument name="qGetNav" type="query">
<cfset var sLU = structNew()>
<cfset var aMenu = arrayNew(1)>
<cfset var aNavMenuItems = arrayNew(1)>
<cfset var sThis = structNew()>
<cfloop query="qGetNav">
<cfset sThis = structNew()>
<cfset sThis.route = qGetNav.Route>
<cfset sthis.textDesc = qGetNav.textDesc>
<cfset sthis.linkTitle = qGetNav.linkTitle>
<cfset sthis.linkTarget = qGetNav.linkTarget>
<cfset sthis.Version = qGetNav.version>
<cfif sthis.Version Eq "CB">
<cfset arrayAppend(aNavMenuItems,sThis.route)>
</cfif>
<cfset sthis.navID = qGetNav.navID>
<cfset sthis.aChildren = arrayNew(1)>
<cfset sLU[qGetNav.navID] = sThis>
<cfif val(qGetNav.navParentID) NEQ 0>
<cfset arrayAppend(sLU[qGetNav.navParentID].aChildren, sThis)>
<cfelse>
<cfset arrayAppend(aMenu, sThis)>
</cfif>
</cfloop>
<cfreturn aMenu>
</cffunction>
<cffunction name="buildListXML" returntype="xml">
<cfargument name="aNav" type="array">
<cfset var navXML="">
<cfxml variable="navXML">
<cfoutput>
#buildList(aNav=arguments.aNav)#
</cfoutput>
</cfxml>
<cfreturn navXML>
</cffunction>
<cffunction name="buildList" returntype="any">
<cfargument name="aNav" type="array">
<cfset var iNav = "">
<ul>
<cfloop array="#aNav#" index="iNav">
<cfoutput>
<cfif iNav.Version Eq "CB">
<cfset iNav.Route="/?event=" & iNav.Route>
<cfelseif iNav.Version Eq "L">
<cfset iNav.Route="http://legacy" & iNav.Route>
</cfif>
<li class="standby" id="id#iNav.navid#">
<a href="#iNav.route#" title="#iNav.linkTitle#" target="#iNav.linkTarget#">
#iNav.textDesc# <font class="menuItemType">(#iNav.Version#)</font>
</a>
<cfif arrayLen(iNav.aChildren) GT 0>
<cfset buildList(iNav.aChildren)>
</cfif>
</li>
</cfoutput>
</cfloop>
</ul>
</cffunction>
来源:https://stackoverflow.com/questions/9832256/coldfusion-xml-menu