2009-04-24 17 views
3

私はクレジットカードの詳細を表すクラスを持っています。私はXML第三者による消費のためにこのクラスをシリアル化していますXMLシリアル化による要素/属性値の書式設定

public int ValidFromMonth { get; set; } 
public int ValidFromYear { get; set; } 
public int ExpiresEndMonth { get; set; } 
public int ExpiresEndYear { get; set; } 

:から有効と有効期限の月と年を表現するために、私はタイプintの4つのプロパティを使用しています。値が10未満

<validFromMonth>02</validFromMonth> 
<validFromYear>09</validFromYear> 
<expiresEndMonth>10</expiresEndMonth> 
<expiresEndYear>14</expiresEndYear> 

は、.NET任意の帰属をサポートしていますであれば第三者が先行ゼロを前置することが私の月と年の値を必要とする(または、私は、カスタム属性を作成することが可能である)ことおそらくフォーマット文字列(例:{0:00})を使用してこのルールを適用しますか?

注:私は、内部書式設定を行う自分のstringプロパティを追加し、私のintプロパティに[XmlIgnore]属性を追加することができることを知っているが、これは二流のソリューションのように感じています。

編集: これは実際には実現可能ではないかと私は思っています。シリアライゼーションは問題ありませんが、デシリアライゼーションを機能させるには、シリアライズされた文字列のフォーマットを解除する必要があります。上の簡単な例ではこれは簡単ですが、より一般的な場合にはうまくいくかどうかはわかりません。

Edit2: 2桁の要件を定義するXMLスキーマは以下のとおりです。

シンプルな型定義:これらの型を使用しています

<xs:simpleType name="CreditCardMonthType"> 
    <xs:annotation> 
    <xs:documentation>Two digit month</xs:documentation> 
    </xs:annotation> 
    <xs:restriction base="xs:string"> 
    <xs:minLength value="2" /> 
    <xs:maxLength value="2" /> 
    </xs:restriction> 
</xs:simpleType> 
<xs:simpleType name="CreditCardYearType"> 
    <xs:annotation> 
    <xs:documentation>Two digit year</xs:documentation> 
    </xs:annotation> 
    <xs:restriction base="xs:string"> 
    <xs:minLength value="2" /> 
    <xs:maxLength value="2" /> 
    </xs:restriction> 
</xs:simpleType> 

クレジットカードの定義:

<xs:attribute name="ExpiryMonth" type="CreditCardMonthType" use="required"> 
<xs:annotation> 
    <xs:documentation>Credit/debt card's expiry month.</xs:documentation> 
</xs:annotation> 
</xs:attribute> 
<xs:attribute name="ExpiryYear" type="CreditCardYearType" use="required"> 
<xs:annotation> 
    <xs:documentation>Credit/debt card's expiry year.</xs:documentation> 
</xs:annotation> 
</xs:attribute> 
<xs:attribute name="StartMonth" type="CreditCardMonthType" use="optional"> 
<xs:annotation> 
    <xs:documentation>Switch card's start month.</xs:documentation> 
</xs:annotation> 
</xs:attribute> 
<xs:attribute name="StartYear" type="CreditCardYearType" use="optional"> 
<xs:annotation> 
    <xs:documentation>Switch card's start year.</xs:documentation> 
</xs:annotation> 
</xs:attribute> 

答えて

3

OK、私の前のコードサンプルを無視する(それはしかし、他の誰かを助けるかもしれないので、私はそれを残しておきます)。

public enum LeadingZeroMonth 
{ 
    [XmlEnum("01")] 
    January, 

    ... 

    [XmlEnum("12")] 
    December 
} 

をして、列挙型へのご使用を変更します:(あなたが今月の列挙型を持っているので

public LeadingZeroMonth ValidFromMonth { get; set; } 

これは実際には非常に良い方法です私はちょうどあなたがXmlEnumAttributeを使用してこれを行うことができます思い出しましたこれは最初からやっていたはずのものです)。

+0

これは素晴らしいです - しかし、私は、私はまだだろうと思いLeadingZeroクラスのアプローチを何年も使用する必要があります。おそらく、 –

+1

。だからこそ私はそれをやめました。私は、彼らがあなたのニーズに応じて別々の回答としてそれらを保つことを保証するのに十分に異なっていたと思った。私は実際に彼らが4桁に年のフィールドを拡大することについて表示されます。つまり、彼らはすでに冗長フォーマット(XML)を使用していますが、今年は2桁しか使わないことで節約していると思いますか?しかし、あなたが彼らのスキーマを使用して立ち往生している場合、私は理解します。いずれにしても、これらの2つのことは、必要なものを達成するのに役立ちます。 –

3

これは、多くのコードですが、それはあなたが望むん。要点は、新しいクラス(この例ではLeadingZero)を作成し、IXmlSerializableを実装してXMLストリームからの読み書き方法を制御できることです。この情報がお役に立てば幸い:

using System; 
    using System.IO; 
    using System.Xml.Serialization; 

namespace StackOverflow 
{ 
    [Serializable] 
    public class LeadingZero : IXmlSerializable 
    { 
     public int Value { get; set; } 

     public LeadingZero() 
     { 
      Value = 0; 
     } 

     public LeadingZero(int value) 
     { 
      this.Value = value; 
     } 

     public override string ToString() 
     { 
      return Value.ToString("00"); 
     } 

     #region IXmlSerializable Members 

     public System.Xml.Schema.XmlSchema GetSchema() 
     { 
      return null; 
     } 

     public void ReadXml(System.Xml.XmlReader reader) 
     { 
      string s = reader.ReadElementString(); 
      int i; 
      if (int.TryParse(s, out i)) 
      { 
       Value = i; 
      } 
     } 

     public void WriteXml(System.Xml.XmlWriter writer) 
     { 
      writer.WriteString(Value.ToString("00")); 
     } 

     #endregion 
    } 

    [Serializable] 
    public class Complex 
    { 
     public LeadingZero ValidFromMonth { get; set; } 
     public LeadingZero ValidFromYear { get; set; } 
     public LeadingZero ExpiresEndMonth { get; set; } 
     public LeadingZero ExpiresEndYear { get; set; } 
    } 

    class Program 
    { 
     static void Main() 
     { 
      var seven = new LeadingZero(7); 

      XmlSerializer xml = new XmlSerializer(typeof(LeadingZero)); 

      StringWriter writer; 

      writer = new StringWriter(); 
      xml.Serialize(writer, seven); 

      string s = writer.ToString(); 

      Console.WriteLine(seven); 
      Console.WriteLine(); 
      Console.WriteLine(s); 

      Console.WriteLine(); 
      var newSeven = xml.Deserialize(new StringReader(s)) as LeadingZero; 
      Console.WriteLine(newSeven ?? new LeadingZero(0)); 

      var complicated = new Complex() 
      { 
       ValidFromMonth = new LeadingZero(7), 
       ValidFromYear = new LeadingZero(2009), 
       ExpiresEndMonth = new LeadingZero(6), 
       ExpiresEndYear = new LeadingZero(2010) 
      }; 

      Console.WriteLine(); 
      writer = new StringWriter(); 

      xml = new XmlSerializer(typeof(Complex)); 
      xml.Serialize(writer, complicated); 
      s = writer.ToString(); 
      Console.WriteLine(s); 

      var newComplicated = xml.Deserialize(new StringReader(s)) as Complex; 
      if (newComplicated != null) 
      { 
       Console.WriteLine(); 
       Console.WriteLine("Woo hoo!"); 
      } 

      Console.ReadLine(); 
     } 
    } 
} 

これは私が得た出力である:

07 

<?xml version="1.0" encoding="utf-16"?> 
<LeadingZero>07</LeadingZero> 

07 

<?xml version="1.0" encoding="utf-16"?> 
<Complex xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http:/ 
/www.w3.org/2001/XMLSchema"> 
    <ValidFromMonth>07</ValidFromMonth> 
    <ValidFromYear>2009</ValidFromYear> 
    <ExpiresEndMonth>06</ExpiresEndMonth> 
    <ExpiresEndYear>2010</ExpiresEndYear> 
</Complex> 

Woo hoo! 
1

この種の要件は、しばしばXMLを理解していない企業に由来します。これがここに当てはまると仮定するのではなく、ゼロデイ型の形式を表すXMLスキーマを提供しましたか?もしそうなら、その日を定義するその部分を投稿することができますか?


EDITは編集上のスキーマを投稿するための

感謝をベース。それは私が心配していたことをもう一度確認しました。あなたの整数は整数ではありません。 <restriction base="xs:string"/>に注意してください。これらは整数ではなく文字列です。

+0

私はそれに応じて私の答えを更新しました –

1

Disadvatage使用XmlEnumは

私は、これはあなたが属性を行うことができます

[XmlIgnore] 
    private int? _startMonth; 

    /// <remarks/> 
    [XmlAttributeAttribute] 
    public string StartMonth 
    { 
     get { return _startMonth == null ? null : _startMonth.ToString().PadLeft(2, '0'); } 
     set { _startMonth = string.IsNullOrEmpty(value) ? (int?)null : int.Parse(value); } 
    } 

Recommandます、それはNULL可能ではないということですNULL可能

+0

情報をくれてありがとう - XmlEnumをnullableにできないことが判明しました。つまり、このアプローチはもはや私たちのニーズに適していません。 –

関連する問題