coldfusion xmlsearch找到多个节点

时间:2012-03-26 08:01:06

标签: xml coldfusion menu coldbox

我有一个广泛的菜单,我想快速搜索和操作菜单项。是否有可能搜索一个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);
            }
        }

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

2 个答案:

答案 0 :(得分:1)

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

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()版本,使用除了前2个字符之外的所有字符。节点id。

答案 1 :(得分: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>