2013-07-03 36 views
5

nedeniyle ondalık ayrıştırmasında XML deserialization çöküyor Bir nesneye XML ayrıştırmaya çalıştığımda System.FormatException atıyorum. Anlayabildiğim kadarıyla, System.Xml.Serialization.XmlSerializer.Deserialize'de kullanılan, ondalık karakter olarak bir nokta beklediği, ancak xml'in bir virgül içerdiği kültürden kaynaklanıyor. aşağıdaki gibiBiçimlendirme

nesne görünür:

 

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; 
    } 
} 
 

xml:

 

<transaction> 
    <transactionDate> 2013-07-02 <transactionDate> 
    <transactionAmount>-459,00</transactionAmount> 
    <transactionDescription>description</transactionDescription> 
    <transactionType>1</transactionType> 
</transaction> 
 
bu benim kendi kültürünü kullanarak ilk ayrıştırır ikinci özelliği sunarak çalışmak yaptık

:

ilave özellik t açığa
 

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; 
     } 
    } 
} 

 

şapka ben orada istemiyorum.

Bu yüzden sorum şu: her öğenin üzerinde yineleme yapmadan ve onu "el ile" nesnesine ayrıştırma/atamadan yapmanın başka bir yolu var mı?

+1

[burada] (http://forums.asp.net/t/1365779.aspx) 'den XmlSerializer'ın [bu W3C şemasını] kullanması gibi görünüyor (http://www.w3.org/TR/xmlschema -2 /) ve makineler/kültürler arasında serileştirme/serileştirme sorunlarından kaçınmak için kültürden nispeten bağımsız olması gerekir. Ben _guess_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ muhtemelen muhtemelen en iyi yoldur (belki "[xmlIgnore]" ile "AmountAsDecimal", sadece biraz daha belirgin) Ne olursa olsun, seri hale getirilmiş nesnelerin tamamen veri aktarım nesneleri olduğu ve uygulamanız/iş mantığınızdan soyutlandığı sürece, o zaman çok fazla acı vermemeliyim umarım. –

+0

Ama ikinci okumada, hangi özellik ayrıştırıcılarını çevirip hangi dizileri çevirmek isteyebilirsiniz. 'Public decimal Amount' değerini, _code_ API'nizde normal şekilde alacağınız/ayarladığınız, ancak [XmlIgnore] 'olarak sahip olduğunuz değer olarak gösterin.Ardından, Get/set uygulamaları özel kültürünüzü biçimlendirecek/ayrıştıracak bir "public string SerializedAmount" özelliğine sahip olmalısınız. En azından bu şekilde, 'Transaction' nesnesinin _write_ için kullandığınız API'nin dizeyi nasıl biçimlendireceğini düşünmesi gerekmez; sadece bir "ondalık" değeri yazar. Yazdığınız şekilde (örneğin, 'SerializedAmount' özelliğini değiştirirseniz) kodunuz umursamıyor. –

cevap

5

XML serializer, standart bir Number ve DateTime biçimi kullanır; bu standart, W3C schema veri türü belirtimi http://www.w3.org/TR/xmlschema-2/'da tanımlanmıştır.

XmlSerializer kodunun CultureInfo numaralı dizgeye dikkat etmesini beklemeyin, kasten kültür/yerel ayardan bağımsız olarak serileştirme/serileştirme yapabilmeniz için standartlaştırılmış bir biçim kullanır.

+0

Yine de, sorgularımdan döndürülen XML virgülle iki katına çıkar. – Softnux

+1

@Softnux, olası bir çözüm bulduğunuzu düşünüyorum. –

+1

+1. @Softnux "bu XML'i yaratır" veya "üçüncü taraf hizmetine karşı çalıştırdığınız sorgular" gibi "sorgularım"? Eğer eski ise, sayı/datetime değerleri için uygun XML formatını kullanmanızı tavsiye ederim. Uzun vadede çok daha kolay olacak. –

2

XML'in oluşturulduğu kültürü biliyorsanız, basit bir çözüm, mevcut iş parçacığının kültürünü seri hale getirmeden önce bu kültüre geçirmektir.

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

En iyi uygulama, bir denemede (veya kullanarak) en az miktarda kod bulundu. Kültürden tasarruf sağladığından, iş parçacığının kültürünü elinize geçmeden önce kaydetmek gerekli değildir. – Steve

5

Bunun yerine ne olabilir/seri decimal serisini kullanılacak bir özellik olması.

Bkz: alabilirsiniz 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; 
    } 
} 

Bu şekilde/o seri hale nasıl dert gerek kalmadan Amount ayarlayın. Bu bir DTO olduğu için, alan nesneniz olarak AmountSerialized10 olmadan başka bir sınıf oluşturabilir (ve AutoMapper gibi bir şeyi kullanarak ağrısız hale getirebilirsiniz).

Kullanımı:

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)); 
} 

Ayrıca transactionDate için biten etiketinde bir yazım hatası yoktu.