2011-06-01 80 views
1

我有兩個XELEMENTS XRXTemp從XELEMENT var + LINQ中提取符合條件的所有元素到XML

MY XR包含:

 <result xmlns="http://abc.com/test"> 
      <report> 
      <unit unit_number="1" id="S1"> 
       <classification>Subject</classification> 
       <claim_reported count="0" status="No claims reported" /> 
      </unit> 
      <unit unit_number="2" id="S2"> 
       <classification>Subject</classification> 
       <claim_reported count="0" status="No claims reported" /> 
      </unit> 
     <unit unit_number="3" id="V1"> 
      <classification>Vehicle</classification> 
      <claim_reported count="1" status="Claims reported" /> 
     </unit> 
    ...... 
    </report> 
</result> 

XTemp包含:

<result xmlns="http://abc.com/test"> 
    <report> 
     <unit unit_number="1" id="S3"> 
      <classification>Subject</classification> 
      <claim_reported count="1" status="Claims reported" /> 
     </unit> 
     <unit unit_number="2" id="S4"> 
      <classification>Subject</classification> 
      <claim_reported count="4" status="Claims reported" /> 
     </unit> 
     <unit unit_number="3" id="V2"> 
     <classification>Vehicle</classification> 
     <claim_reported count="0" status="No claims reported" /> 
     </unit> 
     <unit unit_number="3" id="V3"> 
     <classification>Vehicle</classification> 
     <claim_reported count="2" status="Claims reported" /> 
     </unit> 
     ...... 
    </report> 
</result> 

試圖基於某種condtion從XTemp提取所有<unit>元素,並將它們添加到XR

條件是:獲取其ID爲「V」開頭的所有<unit>元素。

下面的代碼是我能夠想到的最好的代碼。

但是,我得到了Object reference not set to an instance錯誤。

XR.Descendants(xmlns + "unit").LastOrDefault().AddAfterSelf(XTemp.Descendants(xmlns + "unit") 
    .Where(x => x.Element(xmlns + "unit").Attribute("id").Value.ToUpper().Contains("V"))); 

在此先感謝

BB

+0

您是否介意包含您正在使用的XML片段以及導致該行的其他代碼?不要讓我們更難了解你的情況,給我們提供我們需要的信息,不要指望我們必須解決它。 – 2011-06-02 01:21:45

回答

2

你的問題是這段代碼:

.Where(x => x.Element(xmlns + "unit").Attribute("id")... 

在查詢這一點你已經在查詢元素unit。 A unit不包含嵌套的unit,這就是爲什麼你會得到NullReferenceException

將其更改爲:.Where(x => x.Attribute("id")...

就個人而言,我覺得您的查詢難以閱讀。首先,LastOrDefault意味着你可能期望存在一個空值,但是你正在繼續尋找其餘的查詢而沒有解決它。其次,你不需要找到最後的unit元素和AddAfterSelf。相反,你可以直接Addreport元素和元素將被追加到末尾:

var query = xtemp.Descendants(xmlns + "unit") 
       .Where(e => e.Attribute("id").Value.StartsWith("V", StringComparison.InvariantCultureIgnoreCase)); 

xr.Element(xmlns + "report").Add(query); 

另外,注意我是如何檢查的「V」,而忽略大小寫。這被認爲是最佳做法,而不是使用ToUpper


編輯:基礎上的評論,這裏是同時保留非unit節點現有訂單的所有unit節點進行排序的解決方案。該代碼考慮節點是在現有節點之前還是之後發生,或者根本不存在其他節點。

一些假設:

  • XR總是有unit節點
  • 標識遵循現有的字母后面的數字格式。
  • unit節點保持在一起,並且不會散佈在所有其他類型的節點之間。

前兩個假設是微不足道的問題,如果他們不正確的代碼。

var query = xtemp.Descendants(xmlns + "unit") 
       .Where(e => e.Attribute("id").Value.StartsWith("V", StringComparison.InvariantCultureIgnoreCase)); 

var units = xr.Element(xmlns + "report").Elements(xmlns + "unit"); 
var beforeUnit = units.First().ElementsBeforeSelf().FirstOrDefault(); 
var afterUnit = units.Last().ElementsAfterSelf().FirstOrDefault(); 

// order based on ID starting letter, then integer value 
var orderedUnits = units.Concat(query) 
         .OrderBy(e => e.Attribute("id").Value[0]) 
         .ThenBy(e => int.Parse(e.Attribute("id").Value.Substring(1))) 
         .ToList(); 

// remove original unit nodes 
units.Remove(); 

// add ordered units based on their original position 
if (beforeUnit != null) 
{ 
    beforeUnit.AddAfterSelf(orderedUnits); 
} 
else if (afterUnit != null) 
{ 
    afterUnit.AddBeforeSelf(orderedUnits); 
} 
else 
{ 
    xr.Element(xmlns + "report").Add(orderedUnits); 
} 
+0

@Ahmad非常感謝。感謝您提出寶貴的建議。我希望所有的ID以「S」開頭的元素出現,然後是我的XR中以「V」開頭的元素。我怎樣才能做到這一點? – BumbleBee 2011-06-02 18:21:59

+0

除了元素,我的也可能包含其他元素,在這種情況下,我想僅在XR中最後一次發生元素之後才添加提取的元素。 – BumbleBee 2011-06-02 18:33:04

+0

@BumbleBee排序是可能的,但你的第二個評論使問題變得複雜一點。如果其他元素可以在''下存在,他們是否需要按字母順序排序?或者應該保留現有訂單,而只有''元素被排序?前者更容易;後者需要一些額外的咖啡因:) – 2011-06-02 18:37:00