2011-12-06 70 views
3

我正在用Linq解析一個xml文檔,但我遇到了一個我不知道如何處理處理的場景。我發現/嘗試的所有東西似乎都不起作用。正如你在下面看到的(非常簡單的場景),OrderAmount是空的。這是一個十進制字段。當我嘗試在LINQ中處理這個問題時,它不斷轟炸。我曾嘗試使用deimcal ?,使用空檢查等等,似乎沒有任何工作(最有可能的用戶錯誤)。任何建議,將不勝感激。Linq to Xml - Empty Element

如何處理元素爲非字符串(如十進制)並且爲空?

XML:

<Orders> 
    <Order> 
    <OrderNumber>12345</OrderNumber> 
    <OrderAmount/> 
    </Order> 
</Orders> 

LINQ:

List<Order> myOrders = from orders in xdoc.Descendants("Order") 
         select new Order{ 
         OrderNumber = (int)orders.Element("OrderNumber"), 
         OrderAmount = (decimal?)orders.Element("OrderAmount"), 


}.ToList<Order>(); 

回答

4

XElementdecimal?回報null的演員只有當元素實際上null是。

我覺得最可讀的解決辦法是這樣的:

elem.IsEmpty ? null : (decimal?)elem 

您可能希望把這個變成一個擴展方法,如果你經常使用它。或者只是在你的LINQ查詢中使用let來不重複選擇元素的代碼。

from orders in xdoc.Descendants("Order") 
let amountElem = orders.Element("OrderAmount") 
select new Order 
{ 
    OrderNumber = (int)orders.Element("OrderNumber"), 
    OrderAmount = amountElem.IsEmpty ? null : (decimal?)amountElem 
} 

另一種選擇,如果你可以改變XML,簡單地省略元素來表示null。它應該與你已有的代碼一起工作。

編輯:擴展方法會是這個樣子:

static class XElementExtensions 
{ 
    public static decimal? ToNullableDecimal(this XElement elem) 
    { 
     return elem.IsEmpty ? null : (decimal?)elem; 
    } 
} 

而且你會使用這樣的:

OrderAmount = orders.Element("OrderAmount").ToNullableDecimal() 
+0

Hi @svick ...你能告訴我一個在這裏應用擴展方法的例子嗎?我很感激這個信息! – scarpacci

+0

@scarpacci,請參閱編輯。 – svick

+0

@svick ....非常感謝你! – scarpacci

3

如何

OrderAmount = String.IsNullOrEmpty(orders.Element("OrderAmount").Value) ? 
        default(decimal?) : Decimal.Parse(orders.Element("OrderAmount").Value), 

每svick的評論,這可能是更安全的

OrderAmount = String.IsNullOrEmpty(orders.Element("OrderAmount").Value) ? 
        default(decimal?) : (decimal)orders.Element("OrderAmount"), 
+1

使用'decimal.Parse()'這樣是很危險的,因爲它使用文化特定的格式來進行解析。它可能在您的電腦上運行良好,但不適用於我的電腦。我相信在這方面使用'XElement'中的演員是安全的。 – svick

+0

@svick - 足夠公平 - 很容易忘記其他文化 - 我不是一個足夠好的開發人員來編寫世界範圍內使用的東西:) –

0

我想你想要的元素的價值,而不是元素本身。

編輯:如果你真的在保持投設置,這裏要說的是,你可以工作一個通過單元測試的形式來獲得也許更順眼:

private XDocument BuildDocument() 
    { 
     var myAmount = new XElement("OrderNumber", 12345); 
     var myNumber = new XElement("OrderAmount"); 
     var myOrder = new XElement("Order", myAmount, myNumber); 
     var myOrders = new XElement("Orders", myOrder); 
     return new XDocument(myOrders); 
    } 

    private class Order 
    { 
     public int OrderNumber { get; set; } 
     public decimal? OrderAmount { get; set; } 
    } 

    [TestMethod] 
    public void TestMethod() 
    { 
     var myDoc = BuildDocument(); 
     List<Order> myOrders = (from orders in myDoc.Descendants("Order") 
           select new Order 
           { 
            OrderNumber = (int)orders.Element("OrderNumber"), 
            OrderAmount = GetAmount(orders.Element("OrderAmount")) 
           }).ToList<Order>(); 
    } 

    private static decimal? GetAmount(XElement e) 
    { 
     if (e == null || string.IsNullOrEmpty(e.Value)) 
     { 
      return 0.0M; 
     } 
     return (decimal?)e; 
    } 

(你」您仍然需要添加代碼來處理OrderAmount的值類似於「Asdf」的情況)

+0

這就是演員的目的。如果可能的話,他們訪問該元素的值並將其轉換爲指定的類型。但它使用不同的規則作爲無效,而不是所討論的XML。 – svick

+0

那麼,演員陣營調用System.Number.ParseDecimal(字符串),似乎沒有配備處理空值。您將不得不以字符串的形式獲取值,並從那裏進行轉換,轉換爲十進制,爲失敗的分析提供默認值(即包含非數字字符,空值爲空等) –

0

您是如何在Order類中聲明OrderAmount的?嘗試宣告

public decimal? OrderAmount { get; set; } 
+0

這不是問題。如果是,它會導致編譯時錯誤,而不是數據相關的運行時錯誤。 – svick