0

我有一个丰富的菜单,我想在其中快速搜索和操作菜单项。是否可以搜索 id 列表,让我们说一下

list contains ("0,57,19,22,30,31,32,33,34,36,45,53,63,58,59,23,24,25,26,27,28,29,37,38,39,40,41,42,43,44,46,47,48,50,51,52,54,55,16", "45")

示例节点:

<li class="standby" id="id61">

截至目前,我在 cfscript 中使用循环

        if(listLen(IdsToRemove.List,",") GT 1){
            for(i=1;i lte listLen(IdsToRemove.List);i=i+1) {
                valueToFind="li[@id='" & listGetAt(IdsToRemove.List,i) & "']";
                findNode=XmlSearch(MyNavigation.myMenu,"//" & valueToFind);
                Instance.UDFLibrary.XmlDeleteNodes(XmlDocument=MyNavigation.myMenu,Nodes=findNode);
            }
        }

我真的希望搜索一个列表并立即删除所有节点。想法?

4

2 回答 2

1

您可以contains()在 xpath 表达式中使用来搜索字符串。如果将该字符串视为列表,则可以跳过外部循环。

var ids = ListChangeDelims(IdsToRemove.List, ',', ' '); // commas to spaces
var nodes = XmlSearch(MyNavigation.myMenu,"//li[contains(' " & ids & " ', concat(' ', substring(@id,3), ' '))]");

ids 类似于“0 57 19”并且concat(' ', substring(@id,3), ' ')类似于“0”,所以上面的表达式本质上是一个冗长的 ListFind() 版本,使用节点 id 的前 2 个字符以外的所有字符。

于 2012-03-26T08:31:25.367 回答
0

这是我正在使用的完整设置,以防其他人需要帮助:

<cfscript>
    testme=structnew();
    testme.menu=xmlNav(buildNav(qgetNav));
    testme.menustring=tostring(xmlNav(buildNav(qgetNav)));

    testme.valueToFind="li[@id='id56']";
    testme.findNode=XmlSearch(testme.menu,"//" & testme.valueToFind);

    testme.List="0 16 41 42 43 16 41 42 43 16 41 42 43 16 41 42 43 ";
    testme.ids = ListChangeDelims(testme.List,' ',','); // commas to spaces
    testme.nodes = XmlSearch(testme.menu,"//li[contains(' " & testme.ids & " ', concat(' ', substring(@id,3), ' '))]");

    XmlDeleteNodes(XmlDocument=testme.menu,Nodes=testme.nodes);

</cfscript>
<cfdump var="#testme#">

<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="xmlNav" returntype="xml">
    <cfargument name="aNav" type="array">
    <cfset var navXML="">
    <cfxml variable="navXML">
        <cfoutput>
            #xmlNavList(aNav=arguments.aNav)#
        </cfoutput>
    </cfxml>
    <cfreturn navXML>
</cffunction>

<cffunction name="xmlNavList" returntype="any">
    <cfargument name="aNav" type="array">
    <cfargument name="level" type="numeric" default="0">
    <cfset var iNav = "">
    <ul 
        <cfif arguments.level GT 0>
            class="sub-nav-main-links nestingLevel<cfoutput>#arguments.level#</cfoutput>"
        <cfelse>
            id="nav-main-links"
        </cfif> 
        >
        <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 xmlNavList(iNav.aChildren,arguments.level+1)>
                    </cfif>
                </li>
            </cfoutput>
        </cfloop>
    </ul>
</cffunction>

<cffunction name="xmlGetNodePath" access="public" returntype="string"output="false" hint="I take a given XML node and return it's full XML path.">
    <cfargument name="node" type="any" required="true" hint="I am the XML node who's location is being reverse engineered."/>
    <cfset var local={ } />
    <cfset local.fullPath="" />
    <cfset local.marker="udf:xmlGetNodePath" />
    <cfset local.node=arguments.node />
    <cfloop condition="true">
        <cfif ( !structKeyExists( local.node, "xmlParent" ) || !structKeyExists(local.node.xmlParent, "xmlName" ) )>
            <cfbreak />
        </cfif>
        <cfset local.node.xmlAttributes[ local.marker ]=true />
        <cfset local.siblings=xmlSearch( local.node.xmlParent, ( "./" & local.node.xmlName)) />
        <cfloop index="local.siblingIndex" from="1" to="#arrayLen( local.siblings )#"step="1">
            <cfif structKeyExists( local.siblings[ local.siblingIndex ].xmlAttributes,local.marker )>
                <cfset local.fullPath=( "/" & local.node.xmlName & "[" & local.siblingIndex& "]" & local.fullPath ) />
                <cfbreak />
            </cfif>
        </cfloop>
        <cfset structDelete( local.node.xmlAttributes, local.marker ) />
        <cfset local.node=local.node.xmlParent />
    </cfloop>
    <cfreturn local.fullPath />
</cffunction>

<cffunction name="XmlDeleteNodes" access="public" returntype="void" output="false" hint="I remove a node or an array of nodes from the given XML document.">
    <!--- Define arugments. --->
    <cfargument name="XmlDocument" type="any" required="true" hint="I am a ColdFusion XML document object."/>
    <cfargument name="Nodes" type="any" required="false" hint="I am the node or an array of nodes being removed from the given document." />
    <!--- Define the local scope. --->
    <cfset var LOCAL=StructNew() />
    <!---Check to see if we have a node or array of nodes. If weonly have
    one node passed in, let's create an array ofit so we can assume an array
    going forward.--->
    <cfif NOT IsArray( ARGUMENTS.Nodes )>
        <!--- Get a reference to the single node. --->
        <cfset LOCAL.Node=ARGUMENTS.Nodes />
        <!--- Convert single node to array. --->
        <cfset ARGUMENTS.Nodes=[ LOCAL.Node ] />
    </cfif>
    <!---Flag nodes for deletion. We are going to need to deletethese via
    the XmlChildren array of the parent, so weneed to be able to differentiate
    them from siblings.Also, we only want to work with actual ELEMENT nodes,not
    attributes or anything, so let's remove any nodesthat are not element nodes.--->
    <cfloop index="LOCAL.NodeIndex" from="#ArrayLen( ARGUMENTS.Nodes )#" to="1" step="-1">
        <!--- Get a node short-hand. --->
        <cfset LOCAL.Node=ARGUMENTS.Nodes[ LOCAL.NodeIndex ] />
        <!---Check to make sure that this node has an XmlChildrenelement. If it
        does, then it is an element node. Ifnot, then we want to get rid of it.--->
        <cfif StructKeyExists( LOCAL.Node, "XmlChildren" )>
          <!--- Set delet flag. --->
          <cfset LOCAL.Node.XmlAttributes[ "delete-me-flag" ]="true" />
        <cfelse>
          <!---This is not an element node. Delete it from outlist of nodes to delete.--->
          <cfset ArrayDeleteAt(ARGUMENTS.Nodes,LOCAL.NodeIndex) />
        </cfif>
     </cfloop>
    <!---Now that we have flagged the nodes that need to bedeleted, we can
    loop over them to find their parents.All nodes should have a parent, except
    for the rootnode, which we cannot delete.--->
    <cfloop index="LOCAL.Node" array="#ARGUMENTS.Nodes#">
      <!--- Get the parent node. --->
      <cfset LOCAL.ParentNodes=XmlSearch( LOCAL.Node, "../" ) />
      <!---Check to see if we have a parent node. We can'tdelete the root node,
      and we also be deleting otherelements as well - make sure it is all playingnicely
      together. As a final check, make sure thatout parent has children (only
      happens if we aredealing with the root document element).--->
      <cfif (ArrayLen( LOCAL.ParentNodes ) AND StructKeyExists( LOCAL.ParentNodes[1], "XmlChildren" ))>
            <!--- Get the parent node short-hand. --->
            <cfset LOCAL.ParentNode=LOCAL.ParentNodes[ 1 ] />
            <!---Now that we have a parent node, we want to loopover it's children
            to one the nodes flagged asdeleted (and delete them). As we do this, wewant
            to loop over the children backwards so thatwe don't go out of bounds as
            we start to removechild nodes.--->
            <cfloop index="LOCAL.NodeIndex" from="#ArrayLen( LOCAL.ParentNode.XmlChildren )#"to="1" step="-1">
                <!--- Get the current node shorthand. --->
                <cfset LOCAL.Node=LOCAL.ParentNode.XmlChildren[ LOCAL.NodeIndex ] />
                <!---Check to see if this node has been flaggedfor deletion.--->
                <cfif StructKeyExists( LOCAL.Node.XmlAttributes, "delete-me-flag" )>
                        <!--- Delete this node from parent. --->
                        <cfset ArrayDeleteAt(LOCAL.ParentNode.XmlChildren,LOCAL.NodeIndex) />
                        <!---Clean up the node by removing thedeletion flag. This node might still
                        beused by another part of the program.--->
                        <cfset StructDelete(LOCAL.Node.XmlAttributes, "delete-me-flag") />
                    </cfif>
            </cfloop>
        </cfif>
    </cfloop>
    <!--- Return out. --->
    <cfreturn />
</cffunction>
于 2012-03-26T21:21:25.483 回答