2011-12-06 6 views
3

Linq를 사용하여 xml 문서를 구문 분석하고 있지만 처리 방법을 잘 모르겠다. 내가 찾은/시도한 모든 것은 효과가없는 것처럼 보입니다. 아래에서 볼 수 있듯이 OrderAmount가 비어있는 곳 (매우 간단한 시나리오). 이것은 십진수 필드입니다. LINQ에서이 문제를 처리하려고하면 폭탄이 계속 터집니다. 나는 deimcal을 사용하여 해봤습니까?, null 검사 등을 사용하여 아무것도 작동하지 않는 것 같습니다 (대부분의 사용자 오류). 모든 제안을 부탁드립니다.Linq to Xml - 빈 요소

요소가 비 문자열 (십진수 등)이고 비어있는 경우 어떻게 처리합니까?

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

요소가 실제로 nullXElementdecimal?로 돌아 null의 캐스팅을 선언하십시오.

내가 가장 읽을 수있는 솔루션이 같은 생각 :

elem.IsEmpty ? null : (decimal?)elem 

당신이 자주 사용하는 경우, 확장 방법이 점을 넣어 할 수 있습니다. 또는 LINQ 쿼리에서 let을 사용하여 요소를 선택하는 코드를 반복하지 마십시오. 당신이 XML을 변경할 수있는 경우

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 
} 

또 다른 옵션

은 단순히 null을 나타내는 요소를 생략한다. 이미 가지고있는 코드와 잘 작동 할 것입니다.

편집 :이 확장 방법은 같은 것을 보일 것이다 :

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

을 그리고 당신은 다음과 같이 사용합니다 :

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

안녕하세요. @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 (문자열), null을 처리 할 수없는 것으로 나타납니다 호출합니다. 값을 문자열로 가져 와서 거기에서 10 진수로 캐스팅을해야합니다. 실패한 구문 분석의 기본값을 제공합니다 (예 : 숫자가 아닌 문자가 포함되어 있거나 비어 있음). –

0

Order 클래스에서 OrderAmount를 어떻게 선언 했습니까?

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

여기에 문제가 없습니다. . 그렇다면 컴파일 타임 오류가 발생하고 데이터에 따른 런타임 오류는 발생하지 않습니다. – svick