2013-07-25 111 views
0
<Nodes> 
    <Node> 
    <ID>1</ID> 
    <TIDS> 
     <TID>2</TID> 
     <TID>3</TID> 
    </TIDS> 
    </Node> 
    <Node> 
    <ID>2</ID> 
    <TIDS> 
     <TID>4</TID> 
    </TIDS> 
    </Node> 
    <Node> 
    <ID>3</ID> 
    <TIDS> 
     <TID>7</TID> 
    </TIDS> 
    </Node> 
    <Node> 
    <ID>4</ID> 
    <TIDS> 
     <TID>7</TID> 
    </TIDS> 
    </Node> 
    <Node> 
    <ID>5</ID> 
    <TIDS> 
     <TID>7</TID> 
    </TIDS> 
    </Node> 
    <Node> 
    <ID>6</ID> 
    <TIDS> 
     <TID>7</TID> 
    </TIDS> 
    </Node> 
    <Node> 
    <ID>7</ID> 
    </Node> 
</Nodes> 

我想寫查詢將FSELECT TID,再次查詢XML來選擇它的TID 想我在那裏的條件是ID等於1的話,我想出來把2,3,4,7 在我WHERE條件,如果我把ID等於5然後放放7如何編寫遞歸LINQLINQ的XML遞歸選擇

+2

爲什麼要(根據什麼邏輯),它返回2,3,4和7 ID = 1? – Guanxi

+0

@Guanxi我相信OP所尋找的行爲是1的ID返回2和3,然後繼續查找這兩個ID。因此,然後查找2將產生4,並且查找3將產生7(繼續4將會產生7並且向上查找7將不會露出任何東西)。總的來說,從1開始的唯一ID功能已經'發現'將是2,3,4和7. – diceguyd30

+0

沒問題......謝謝。 – Guanxi

回答

0

[R ecursive LINQ更是一個派對招比你預期的要在生產代碼中使用任何東西的,但這裏的做到這一點的一種方法:

XElement nodes = /* load your xml */; 

Func<XElement, int, IEnumerable<int>> query = null; 

/* BAD CODE, DO NOT USE! */ 
query = (x,id) => 
    x.Elements("Node") 
    .Where (node => (int)node.Element("ID") == id) // find our node 
    .Descendants("TID")  // this will be empty in the base case 
    .Select (tid => (int)tid) 
    .SelectMany(tid => 
     query(x,tid)   // recurse 
     .Concat(new[]{tid}) // keep the current TID if its node had no TIDs 
    ) 
    .Distinct(); 

var resultOf7423 = query(nodes, 1); 
var resultOf7 = query(nodes, 5); 
/* END BAD CODE (I HOPE) */ 

這是莫名其妙的,脆弱的代碼,你幾乎肯定不應該用它。相反,你可以創建一個擴展方法關閉的XElement

public static IEnumerable<int> SelectRelatedIds(this XElement element, int id) 
{ 
    if(element == null) throw new ArgumentNullException("element"); 
    return SelectRelatedIdsIterator(element, id) 
       .Where(i => i != id) 
       .Distinct(); 
} 

private static IEnumerable<int> SelectRelatedIdsIterator(XElement element, int id) 
{ 
    yield return id; 

    var tids = element.Elements("Node") 
       .Where (node => (int)node.Element("ID") == id) 
       .Descendants("TID"); 

    foreach (int tid in tids) 
     foreach(var i in SelectRelatedIdsIterator(element, tid)) 
      yield return i; 
} 

這使得含有遞歸和很容易理解的(至少一旦你身邊的迭代器塊的頭)。它也是LINQ友好的,並且可能以第一種方式不可組合的方式組合。

1
var result = xml.Elements() 
    // Find element with <ID>1</ID> 
    .Where(x => x.Elements().Any(d => d.Name == "ID" && d.Value == "1")) 
    // Find element <TIDS> 
    .Elements().Where(x => x.Name == "TIDS") 
    // Find elements <TID> 
    .Elements().Where(x => x.Name == "TID") 
    // Select values 
    .Select(x => x.Value); 

筆記,我做了xml變量是這樣的:

XElement xml = XElement.Parse (@"<Nodes> 
    <Node> 
    <ID>1</ID> 
    <TIDS> 
     <TID>2</TID> 
     <TID>3</TID> 
    </TIDS> 
    </Node> 
    <Node> 
    <ID>2</ID> 
    <TIDS> 
     <TID>4</TID> 
    </TIDS> 
    </Node> 
    <Node> 
    <ID>3</ID> 
    <TIDS> 
     <TID>7</TID> 
    </TIDS> 
    </Node> 
    <Node> 
    <ID>4</ID> 
    <TIDS> 
     <TID>7</TID> 
    </TIDS> 
    </Node> 
    <Node> 
    <ID>5</ID> 
    <TIDS> 
     <TID>7</TID> 
    </TIDS> 
    </Node> 
    <Node> 
    <ID>6</ID> 
    <TIDS> 
     <TID>7</TID> 
    </TIDS> 
    </Node> 
    <Node> 
    <ID>7</ID> 
    </Node> 
</Nodes>"); 
+0

+1瞭解他在什麼。 – James

+0

@詹姆斯 - 謝謝,我不知道我是否正確 - 但我認爲如果你把我的代碼放在一個函數中,然後遞歸地調用它,那可能是他想要的。 – Hogan

+0

這隻會返回初始ID的TID值。它不會再爲每個TID查詢。 – jzm

0

GetTids返回你傳遞的IDTIDs列表的功能。初始ID通過後,它返回一個列表(tidIndex)。然後循環運行,並且每個TID值用於查詢XML並被添加到tidList

List<string> TidList() 
{ 
    var xml = XDocument.Load(@"C:\PathToXml\File.xml"); 

    var tidIndex = GetTids(xml, "1").ToList(); 
    var tidList = new List<string>(tidIndex); 

    foreach (var tid in tidIndex) 
     tidList.AddRange(GetTids(xml, tid)); 

    return tidList; 
} 

static IEnumerable<string> GetTids (XDocument xml, string id) 
{ 
    return xml.Descendants("Node") 
     .Where(x => x.Element("ID").Value == id) 
     .Descendants("TID") 
     .Select (s => s.Value); 
} 

這將返回:

enter image description here