2012-07-28 12 views
1

我正在嘗試創建章軍官和他們各自的職位清單。數據來自通過Web服務訪問的一系列XML鍵值對(Key:Member_Name,Value:Joe Member。Key:Position_Name,Value:President,等等。)給定章節的每個主管都有自己的Member_Name和Position_Name。ColdFusion - 如何遍歷XML輸出並添加到結構或數組?

我用僅會返回整個對象工作的API,所以我成立了一個數組來轉換XML名稱和持有的一切:

<cfset keyValue = xmlSearch(soapBody,"//*[local-name()='KeyValueOfstringanyType']") /> 

我的想法是,通過該數組循環,爲關鍵MEMBER_NAME和Position_Name的所有實例,該值添加到一個結構:

<cfset chapterOfficers=structNew()> 
<cfloop index="i" from="1" to="#arrayLen(keyValue)#"> 
    <cfif keyValue[i].Key.xmlText EQ 'Member_Name'> 
     <cfset chapterOfficers.Name=keyValue[i].Value.xmlText> 
    </cfif> 
    <cfif keyValue[i].Key.xmlText EQ 'Position_Name'> 
     <cfset chapterOfficers.Position = keyValue[i].Value.xmlText> 
    </cfif> 
    <cfif keyValue[i].Key.xmlText EQ 'Term_Name'> 
     <cfset chapterOfficers.Term = keyValue[i].Value.xmlText> 
    </cfif> 
</cfloop> 

傾銷這種結構給了我一個人的名字,那個人的位置,他們的任期漂亮整潔的小表 - 但只有一個(恰好是最後一個入口在XML文件中)。即使添加i = i + 1也沒有任何影響 - 這幾乎就像循環從最後開始,而不是繼續。

我嘗試添加的東西向結構,確實看透了一切循環的其他方式,但鍵/值對在一個不相關的順序出來。我知道結構不是有序的,但我需要有一些方法來從XML輸出中排序數據。我也嘗試過各種其他循環,試圖將一系列像這樣的小結構添加到數組中。它的工作,但再次,只爲那個人 - 沒有真正的「循環」似乎發生!我可以同時看到所有我需要的信息 - 也許這是爲了讓我做錯了什麼?

謝謝大家提前,我感謝任何建議或在正確的方向輕推!

UPDATE:不知道這是否有幫助,但現在我在我正在使用的循環中交換了To和From的值,並將步驟設置爲-1,並且它給了我名單上的第一個人。但仍然沒有循環。

更新:謝謝彼得,這裏是我一起工作的XML的例子:

<b:KeyValueOfstringanyType> 
        <b:Key>Member_Guid</b:Key> 
        <b:Value i:type="d:string">006e1c09-25f9-4178-86de-13c3e63200ce</b:Value> 
       </b:KeyValueOfstringanyType> 
       <b:KeyValueOfstringanyType> 
        <b:Key>Member_Type</b:Key> 
        <b:Value i:type="d:string">Entity</b:Value> 
       </b:KeyValueOfstringanyType> 
       <b:KeyValueOfstringanyType> 
        <b:Key>Member_Name</b:Key> 
        <b:Value i:type="d:string">Member, Joe</b:Value> 
       </b:KeyValueOfstringanyType> 
       <b:KeyValueOfstringanyType> 
        <b:Key>Position_Guid</b:Key> 
        <b:Value i:type="d:string">02ae1c09-5779-4891-8cd1-05cf475cf5af</b:Value> 
       </b:KeyValueOfstringanyType> 
       <b:KeyValueOfstringanyType> 
        <b:Key>Position_Type</b:Key> 
        <b:Value i:type="d:string">CommitteePosition</b:Value> 
       </b:KeyValueOfstringanyType> 
       <b:KeyValueOfstringanyType> 
        <b:Key>Position_Name</b:Key> 
        <b:Value i:type="d:string">President</b:Value> 
       </b:KeyValueOfstringanyType> 
       <b:KeyValueOfstringanyType> 
        <b:Key>Term_Guid</b:Key> 
        <b:Value i:type="d:string">044e1c09-a90b-495f-891f-afa13e653dee</b:Value> 
       </b:KeyValueOfstringanyType> 
       <b:KeyValueOfstringanyType> 
        <b:Key>Term_Type</b:Key> 
        <b:Value i:type="d:string">CommitteeTerm</b:Value> 
       </b:KeyValueOfstringanyType> 
       <b:KeyValueOfstringanyType> 
        <b:Key>Term_Name</b:Key> 
        <b:Value i:type="d:string">2011-2012</b:Value> 
       </b:KeyValueOfstringanyType> 

重複對文件每章官。

更新:這裏是我想出的代碼。它做我想做它,但有更好的方法來做到這一點,我相信...

首先,我從SOAP響應的結果,「深入」到我需要的級別,和然後剝離出特定於XML的東西和使數據進入一個可用的數組:

<cfset soapBody = xmlParse(cfhttp.fileContent)> 
<cfset soapBody = soapBody['s:Envelope']['s:Body'].QueryResponse.QueryResult.Objects.anyType.Fields /> 
<cfset keyValue = xmlSearch(soapBody,"//*[local-name()='KeyValueOfstringanyType']") /> 

然後

<cfset chapterOfficers=arrayNew(2)> 
<cfset x=1> 
<cfset y=1> 

<cfloop index="i" from="1" to="#arrayLen(keyValue)#"> 
    <cfif keyValue[i].Key.xmlText EQ 'Member_Name'> 
     <cfset memberName = keyValue[i].Value.xmlText> 
     <cfset chapterOfficers[x][y]=#memberName#> 
     <cfset y=y+1> 
    </cfif> 
    <cfif keyValue[i].Key.xmlText EQ 'Position_Name'> 
     <cfset positionName = keyValue[i].Value.xmlText> 
     <cfset chapterOfficers[x][y]=#positionName#> 
     <cfset x=x+1> 
     <cfset y=1> 
    </cfif> 
    <cfif keyValue[i].Key.xmlText EQ 'Member_Guid'> 
     <cfset memberGuid = keyValue[i].Value.xmlText> 
     <cfset chapterOfficers[x][3]=#memberGuid#> 
    </cfif> 
</cfloop> 

我做一些其它的處理,檢查變量存在,等等,然後輸出軍官姓名和他們各自的職位

<cfloop from="1" to="#arrayLen(chapterOfficers)#" index="x"> 
    <p> 
     <cfoutput><a href="OfficerDetail.cfm?sessionGuid=<cfoutput>#URL.sessionGuid#</cfoutput>&memberGuid=<cfoutput>#chapterOfficers[x][3]#</cfoutput>">#chapterOfficers[x][1]#</a></cfoutput><br /> 
     <cfoutput>#chapterOfficers[x][2]#</cfoutput><br /> 
    </p> 
</cfloop> 

我能夠將Member_Guid添加到數組中並使用它,因此網站訪問者可以點擊一個人的姓名以查看更多詳細信息(公司,電子郵件地址等)。這就是它!你怎麼看?再次感謝您抽出時間,我非常感謝!

+0

的Structs只能包含一個組鍵 - 如果你需要一個額外的維度需要放置結構中的處於陣列(或使用查詢記錄) 。但是,您也不需要循環遍歷所有的鍵,而是正確地處理XML - 在沒有看到XML結構的情況下很難說更多的東西,所以發佈XML數據的樣本(帶有任何被屏蔽/刪除的敏感信息)。 – 2012-07-29 01:00:00

+0

彼得你好,非常感謝你的幫助。下面是一個XML示例: – daltec 2012-07-29 01:33:43

+0

@PeterBoughton我在原始文章中添加了一些XML示例。命名空間比這裏展示的更廣泛,但這有幫助嗎?如果您需要更多信息,請告知我們,並非常感謝您的幫助。 – daltec 2012-07-29 01:42:26

回答

1

這是我怎麼可能會解決這個問題:

<cfset var ChapterOfficers = StructNew()> 
<cfset var CurMemberGuid = '' /> 

<cfloop index="local.CurPair" array=#keyValue#> 

    <cfif CurPair.Key.XmlText EQ 'Member_Guid' > 
     <cfset CurMemberGuid = CurPair.Value.XmlText /> 
     <cfset ChapterOfficers[CurMemberGuid] = StructNew() /> 
    <cfelse> 
     <cfset ChapterOfficers[CurMemberGuid][CurPair.Key.XmlText] = CurPair.Value.XmlText /> 
    </cfif> 

</cfloop> 

它利用現有的XmlSearch你所做的,並假定Member_Guid總是第一個鍵/值對。我已經使用了var/local作用域,假設這是進入一個函數內部(它可能應該是這樣),但是如果不是這樣,就把它們移除。

它使用結構體,因此查找特定的GUID很容易,但順序不會被保留(儘管如果必要,您可以保留一個單獨的數組來執行該操作),並且您不必記住哪個數組位置與哪個鍵。

如果你想基於其他字段查找,你也可以將數據轉換成一個查詢,像這樣:

<cfset var ChapterOfficers = QueryNew('Member_Guid,Member_Type,Member_Name,Position_Guid,Position_Type,Position_Name,Term_Guid,Term_Type,Term_Name')> 
<cfset var CurRow = 1 /> 

<cfloop index="local.CurPair" array=#keyValue#> 

    <cfif CurPair.Key.XmlText EQ 'Member_Guid' > 
     <cfset QueryAddRow(ChapterOfficers) /> 
    </cfif> 

    <cfset QuerySetCell(ChapterOfficers,CurPair.Key.XmlText,CurPair.Value.XmlText) /> 

</cfloop> 

這維持秩序,讓更廣泛的查找更容易,也使得它是否容易你主要用途是直接輸出到HTML。

我已經硬編碼列鍵,但你也可以做一個預循環來整理那些第一,如果他們是可以改變的東西。


希望這一切都有道理?

+0

哇,彼得,這太棒了!我對你最初的例子中的嵌套結構非常滿意 - 這使得在循環中輸出成員信息變得更容易。它也幫助我建立鏈接。我在我的網站上的其他地方廣泛使用了我的舊方法,但是您的方法更加高效和簡潔,而且說實話,現在我可以看到它並且仔細考慮它。非常感謝!我必須承認,我仍然試圖去處理你的第二個例子,但我現在正在試驗它。再次感謝Peter,這真是太棒了,我非常感謝你的幫助和建議! – daltec 2012-07-29 22:38:20

0

ColdFusion的10或Railo 4,你可以使用Underscore.cfc library幫助清理您的解決方案了很多:

<cfscript> 
    soapBody = XmlParse(cfhttp.filecontent); 
    fields = xmlSearch(soapBody,"//*[local-name()='Fields']"); 
    chapterOfficers = _.map(fields, function (field) { 
     var officer = {}; 
     _.each(field.xmlChildren, function (KeyValueOfstringanyType) { 
      var key = KeyValueOfstringanyType['b:Key'].xmlText; 
      var value = KeyValueOfstringanyType['b:Value'].xmlText; 
      officer[key] = value; 
     }); 
     return officer; 
    }); 
</cfscript> 

<cfoutput> 
<cfloop array="#chapterOfficers#" index="officer"> 
    <a href="OfficerDetail.cfm?sessionGuid=#URL.sessionGuid#&memberGuid=#officer.Member_Guid#">#officer.Member_Name#</a> 
    #officer.Position_Name#<br /> 
</cfloop> 
</cfoutput> 

現在是不是更好?我不確定你的SOAP響應是什麼樣的,但你應該能夠調整xmlSearch()以匹配KeyValueOfstringanyType的父元素。我還爲您刪除了所有不必要的cfoutputs。另外,我建議切換到JSON而不是XML。這很容易解析。

(聲明:我寫的Underscore.cfc庫)

+0

嗨,Russ看起來更容易處理 - 如果我們轉向CF10,我會給它一個鏡頭。謝謝!感謝JSON的提示,我很感激。 – daltec 2012-08-04 20:37:38