2013-10-17 60 views
1

如果當前的「名稱」元素爲空或爲空,則應該使用前一個元素的「名稱」值。第一個元素名稱永遠不會爲空或空白。自己獲取元素

我需要得到由先前的元素「名稱」值在當前「名稱」元素的值是null或空:

List<ScripTbl> ScripData = ScrpHldNode.Descendants(ns + "Scrp").Select(x => new ScripTbl 
{ 
    ID = sID, 
    //need help with the line below.... 
    ScripShare = (!string.IsNullOrEmpty((String)x.Element(ns + "Name")) ? (String)x.Element(ns + "Name") : (x.ElementsBeforeSelf().Count() > 0 ? (String)x.ElementsBeforeSelf().Last().Element(ns + "Name") : "")), 
    ScripOpenBalanceDue = (String)x.Element(ns + "OpBal"), 
    ScripClosingBalance = (String)x.Element(ns + "ClBal"), 
    ScripTransaction = (String)x.Element(ns + "Tran"), 
    ScripMovement = (String)x.Element(ns + "Move"), 
    ScripFooter = sScripFooter, 
    Seq = x.ElementsBeforeSelf().Count() + 1, 
    ScripSectorCode = (String)x.Element(ns + "SecCde"), 
    ScripClosingPrice = (String)x.Element(ns + "ClPrce"), 
    SplitIndicator = (!string.IsNullOrEmpty((String)x.Element(ns + "Name")) ? (x.ElementsBeforeSelf().Count() > 0 && (String)x.Element(ns + "Name") == (String)x.ElementsBeforeSelf().Last().Element(ns + "Name") ? "1" : "0") : "0") 
}).ToList(); 

和XML:

<ScrpHld xmlns="http://www.website.co.za/namespace"> 
<Scrp> 
    <Name>Company Name Number 1</Name> 
    <SecCde>1366J</SecCde> 
    <Tran>SOLD</Tran> 
    <OpBal>0</OpBal> 
    <Move>-2000</Move> 
</Scrp> 
<Scrp> 
    <Tran>ELECTRONIC SETTLEMENT</Tran> 
    <Move>2000</Move> 
    <ClPrce>25045.00</ClPrce> 
    <ClBal>0</ClBal> 
</Scrp> 
<Scrp> 
    <Name>Company Name Number 2</Name> 
    <SecCde>1313J</SecCde> 
    <Tran>SOLD</Tran> 
    <OpBal>10000</OpBal> 
    <Move>-90500</Move> 
</Scrp> 
<Scrp> 
    <Tran>ELECTRONIC SETTLEMENT</Tran> 
    <Move>80500</Move> 
    <ClPrce>3392.00</ClPrce> 
    <ClBal>0</ClBal> 
</Scrp> 
</ScrpHld> 

回答

2

使用PreviousNode代替ElementsBeforeSelf,它會更容易。爲了增加答案的可讀性,我分成多行。

行應類似於此

ScripShare = (x.Element(ns + "Name") != null 
       ? (string)x.Element(ns + "Name") 
       : (x.PreviousNode != null 
          ? ((XElement)x.PreviousNode).Element(ns + "Name").Value 
          : string.Empty)), 

如果你的XML將包含註釋或元素中任何其他文本,你應該檢查前一個節點是XElement類型,而不是一個COMENT(XComent)或中文本(XText),那麼在這種情況下,它會很容易使用ElementsBeforeSelf

ScripShare = (x.Element(ns + "Name") != null 
        ? (string)x.Element(ns + "Name") 
        : (x.NodesBeforeSelf().Last(e => e.NodeType == XmlNodeType.Element) != null 
           ? ((XElement)x.NodesBeforeSelf().Last(e => e.NodeType == XmlNodeType.Element)).Element(ns + "Name").Value 
           : string.Empty)), 
+0

'System.Xml.Linq.XNode'沒有包含'Element'的定義,也沒有找到接受'System.Xml.Linq.XNode'類型的第一個參數的擴展方法'Element' – BossRoss

+0

對不起,我忘了將PreviousNode投射到XElement,我已經更新了答案 –

+0

無法投射System.Xml.Linq.XText類型的對象來鍵入System.Xml.Linq.XElement – BossRoss

0

試試這個:

private static string ns = "{http://www.website.co.za/namespace}"; 
    private static string getName(XElement x) { 
     if (x == null) 
      throw new InvalidOperationException("First elements has no Name"); 
     var val = (string) x.Element(ns + "Name"); 
     return val ?? getName((XElement)x.PreviousNode); 
    } 

    static void Main(string[] args) 
    { 
     string xml = @"<ScrpHld xmlns=""http://www.website.co.za/namespace""> 
     <Scrp> 
      <Name>Company Name Number 1</Name> 
      <SecCde>1366J</SecCde> 
      <Tran>SOLD</Tran> 
      <OpBal>0</OpBal> 
      <Move>-2000</Move> 
     </Scrp> 
     <Scrp> 
      <Tran>ELECTRONIC SETTLEMENT</Tran> 
      <Move>2000</Move> 
      <ClPrce>25045.00</ClPrce> 
      <ClBal>0</ClBal> 
     </Scrp> 
     <Scrp> 
      <Name>Company Name Number 2</Name> 
      <SecCde>1313J</SecCde> 
      <Tran>SOLD</Tran> 
      <OpBal>10000</OpBal> 
      <Move>-90500</Move> 
     </Scrp> 
     <Scrp> 
      <Tran>ELECTRONIC SETTLEMENT</Tran> 
      <Move>80500</Move> 
      <ClPrce>3392.00</ClPrce> 
      <ClBal>0</ClBal> 
     </Scrp> 
     </ScrpHld>"; 
     XDocument doc = XDocument.Parse(xml); 
     var result = doc.Descendants(ns + "Scrp").Select(x => new 
      { 
       Name = getName(x) 
      }); 
     foreach (var item in result) 
     { 
      Console.WriteLine(item.Name); 
     } 

該方法使用遞歸方法,即使兩個連續元素沒有名稱,它們也會具有前一個元素的名稱。

0

您可以捕捉當前的名字在選擇方法範圍聲明變量:

string name = ""; 
scripData = ScrpHldNode.Descendants(ns + "Scrp") 
         .Select(scrp => { 
          var currentName = (string)scrp.Element(ns + "Name"); 
          if (!String.IsNullOrEmpty(currentName)) 
           name = currentName; 

          return new ScripTbl { 
           ScripShare = name 
           // ... 
          }; 
         }); 

沒有遞歸,沒有遍歷XML樹前面的元素。


如果你只需要檢查缺少name元素,那麼代碼可縮短至

string name = ""; 
var scripData = from scrp in ScrpHldNode.Descendants(ns + "Scrp") 
       let currentName = (string)scrp.Element(ns + "Name") ?? name 
       select new ScripTbl { 
        ScripShare = (name = currentName) 
        // ... 
       }; 

這是短(由於ScripShare分配期間空合併運算符的使用和棘手的名稱分配),但我會選擇更長更明顯的代碼。