coldfusion xmlsearch найти несколько узлов - PullRequest
0 голосов
/ 26 марта 2012

У меня есть обширное меню, в котором я хотел бы быстро искать пункты меню и манипулировать ими. Можно ли искать список идентификаторов, скажем что-то вроде

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 ]

1 голос
/ 26 марта 2012

Вы можете использовать contains() в выражениях xpath для поиска по строке.Если вы рассматриваете эту строку как список, вы можете пропустить внешний цикл.

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

Идентификаторы будут выглядеть как «0 57 19», а concat(' ', substring(@id,3), ' ') будет что-то вроде «0», поэтому приведенное выше выражениепо сути, длинная версия ListFind (), использующая все, кроме первых 2 символов узлов id.

0 голосов
/ 27 марта 2012

Вот полная настройка, которую я использую в случае, если другим нужна помощь с этим:

<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>
...