2013-07-03 29 views
5

Tôi nhận được một lỗi System.FormatException khi tôi cố phân tích cú pháp XML thành một đối tượng. Theo như tôi có thể nói, đó là do văn hóa được sử dụng trong System.Xml.Serialization.XmlSerializer.Deserialize, mà dự kiến ​​một dấu chấm làm ký tự thập phân, nhưng xml chứa dấu phẩy.Xảy ra lỗi deserialization trên phân tích cú pháp thập phân do định dạng

Đối tượng trông như sau:

 

public sealed class Transaction 
{ 
    [XmlElement("transactionDate")] 
    public DateTime TransactionDate { get; set; } 

    [XmlElement("transactionAmount")] 
    public decimal Amount { get; set; } 

    [XmlElement("transactionDescription")] 
    public string Description { get; set; } 

    [XmlElement("transactionType")] 
    public int Type { get; set; } 

    public static Transaction FromXmlString(string xmlString) 
    { 
     var reader = new StringReader(xmlString); 
     var serializer = new XmlSerializer(typeof(Transaction)); 
     var instance = (Transaction) serializer.Deserialize(reader); 

     return instance; 
    } 
} 
 

Các xml:

 

<transaction> 
    <transactionDate> 2013-07-02 <transactionDate> 
    <transactionAmount>-459,00</transactionAmount> 
    <transactionDescription>description</transactionDescription> 
    <transactionType>1</transactionType> 
</transaction> 
 

Tôi đã thực hiện nó hoạt động bằng cách giới thiệu một tài sản thứ hai mà phân tích là người đầu tiên sử dụng nền văn hóa của riêng tôi:

 

namespace MyNamespace 
{ 
    [XmlRoot("transaction"), XmlType("Transaction")] 
    public sealed class Transaction 
    { 
     [XmlElement("transactionDate")] 
     public DateTime TransactionDate { get; set; } 

     [XmlElement("transactionAmount")] 
     public string Amount { get; set; } 

     public decimal AmountAsDecimal { 
      get 
      { 
       decimal value; 
       Decimal.TryParse(Amount, NumberStyles.Any, CultureInfo.CreateSpecificCulture("sv-SE"), out value); 
       return value; 
      } 
     } 

     [XmlElement("transactionDescription")] 
     public string Description { get; set; } 

     [XmlElement("transactionType")] 
     public int Type { get; set; } 

     public static Transaction FromXmlString(string xmlString) 
     { 
      var reader = new StringReader(xmlString); 
      var serializer = new XmlSerializer(typeof(Transaction)); 
      var instance = (Transaction) serializer.Deserialize(reader); 

      return instance; 
     } 
    } 
} 

 

hiển thị thêm thuộc tính t mũ tôi không muốn ở đó.

Vì vậy, câu hỏi của tôi là: có cách nào khác để làm điều này, mà không cần lặp qua từng phần tử và phân tích cú pháp/gán nó cho đối tượng "theo cách thủ công" không?

+1

Từ [tại đây] (http://forums.asp.net/t/1365779.aspx) có vẻ như XmlSerializer đang sử dụng [lược đồ W3C này] (http://www.w3.org/TR/xmlschema -2 /) và được coi là tương đối độc lập với văn hóa để tránh các vấn đề serialization/deserialization trên các máy móc/văn hóa. Tôi sẽ _guess_ rằng những gì bạn đang làm bây giờ có lẽ là cách tốt nhất (có thể tô điểm 'AmountAsDecimal' với' [XmlIgnore] 'chỉ vì vậy nó là một chút rõ ràng hơn). Bất kể, miễn là các đối tượng được tuần tự hóa của bạn hoàn toàn là các đối tượng chuyển dữ liệu và được trừu tượng hóa từ logic ứng dụng/kinh doanh của bạn, thì nó không làm tổn thương quá nhiều tôi hy vọng. –

+0

Nhưng vào lần đọc thứ hai, bạn có thể muốn lật thuộc tính nào phân tích cú pháp và tuần tự hóa nào. Hiển thị 'Số thập phân công khai' làm giá trị mà bạn sẽ nhận được/đặt bình thường trong _code_ API của bạn nhưng có nó là' [XmlIgnore] '.Sau đó, có một thuộc tính 'chuỗi công khai SerializedAmount' có cài đặt get/set sẽ định dạng/phân tích cú pháp văn hóa chuyên ngành của bạn. Ít nhất theo cách này, API bạn sử dụng để _write_ đối tượng 'Transaction' không phải nghĩ cách định dạng chuỗi; nó chỉ viết một giá trị 'thập phân'. Nếu cách bạn viết nó (bạn thay đổi thuộc tính 'SerializedAmount' chẳng hạn) thì mã của bạn không quan tâm. –

Trả lời

5

Trình nối tiếp XML sử dụng định dạng Số và Ngày giờ chuẩn, tiêu chuẩn được xác định trong đặc tả dữ liệu lược đồ W3C http://www.w3.org/TR/xmlschema-2/.

Đừng mong đợi XmlSerializer để chú ý đến chủ đề của CultureInfo, nó cố ý sử dụng định dạng chuẩn để đảm bảo bạn có thể tuần tự hóa/deserialize độc ​​lập của văn hóa/miền địa phương.

+0

Mặc dù vậy, XML được trả về từ các truy vấn của tôi chứa gấp đôi dấu phẩy. – Softnux

+1

@Softnux, tôi cho rằng bạn đã tìm thấy một giải pháp khả thi. –

+1

+1. @Softnux "truy vấn của tôi" như trong "tạo XML này" hoặc "truy vấn bạn thực thi đối với dịch vụ của bên thứ ba"? Nếu trước đây tôi khuyên bạn nên sử dụng định dạng XML thích hợp cho các giá trị số/giá trị ngày giờ. Sẽ dễ dàng hơn nhiều trong thời gian dài. –

2

Nếu bạn biết văn hóa mà XML đã được tạo ra, một giải pháp dễ dàng là chuyển văn hóa của luồng hiện tại sang văn hóa đó trước khi deserializing.

System.Globalization.CultureInfo oCurrentCulture = null; 
    try 
    { 
     // Save the current culture 
     oCurrentCulture = System.Threading.Thread.CurrentThread.CurrentCulture; 
     System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("de-DE"); 

     // Do your work 
    } 
    finally 
    { 
        // Restore the saved culture 
     System.Threading.Thread.CurrentThread.CurrentCulture = oCurrentCulture; 
    } 
+0

Tôi đã tìm thấy phương pháp hay nhất là có số lượng mã ít nhất trong một lần thử (hoặc sử dụng). Kể từ khi tiết kiệm ra khỏi văn hóa là không cần thiết để được trong vòng thử tiết kiệm văn hóa của thread trước khi tay là thích hợp – Steve

5

Thay vào đó, bạn có thể sử dụng thuộc tính sẽ được sử dụng để tuần tự hóa/deserialize decimal.

Xem: Partially deserialize XML to Object

[XmlType("transaction")] 
public sealed class Transaction 
{ 
    [XmlElement("transactionDate")] 
    public DateTime TransactionDate { get; set; } 

    [XmlIgnore] 
    public decimal Amount { get; set; } 

    [XmlElement("transactionAmount")] 
    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] 
    public string AmountSerialized 
    { 
     get 
     { 
      return Amount.ToString(CultureInfo.CreateSpecificCulture("sv-SE")); 
     } 
     set 
     { 
      decimal amount; 
      Decimal.TryParse(value, NumberStyles.Any, CultureInfo.CreateSpecificCulture("sv-SE"), out amount); 
      Amount = amount; 
     } 
    } 

    [XmlElement("transactionDescription")] 
    public string Description { get; set; } 

    [XmlElement("transactionType")] 
    public int Type { get; set; } 

    public static Transaction FromXmlString(string xmlString) 
    { 
     var reader = new StringReader(xmlString); 
     var serializer = new XmlSerializer(typeof(Transaction)); 
     var instance = (Transaction) serializer.Deserialize(reader); 

     return instance; 
    } 
} 

Bằng cách này bạn có thể nhận/thiết lập các Amount mà không cần phải lo lắng về việc làm thế nào nó là serialized. Vì đây là DTO, bạn có thể tạo một lớp khác mà không cần AmountSerialized làm đối tượng miền của bạn (và sử dụng một cái gì đó như AutoMapper để làm cho việc chuyển đổi không đau).

Cách sử dụng:

var data = @"<transaction> 
       <transactionDate>2013-07-02</transactionDate> 
       <transactionAmount>-459,00</transactionAmount> 
       <transactionDescription>description</transactionDescription> 
       <transactionType>1</transactionType> 
      </transaction>"; 

var serializer = new XmlSerializer(typeof(Transaction)); 

using(var stream = new StringReader(data)) 
using(var reader = XmlReader.Create(stream)) 
{ 
    Console.Write(serializer.Deserialize(reader)); 
} 

Cũng đã có một lỗi đánh máy trong thẻ kết thúc cho transactionDate.

Các vấn đề liên quan