2009-04-24 6 views
3

Ich habe eine Klasse, die Kreditkartendaten darstellt. Für die Darstellung gültig ab und Ablauf Monaten und Jahren verwende ich vier Eigenschaften des Typs int:Formatierung Element/Attribut-Werte mit XML-Serialisierung

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

Ich bin XML Serialisierung dieser Klasse für den Verzehr durch einen Dritten. Das Dritter bedarf meinen Monat und Jahr Werte mit einer führenden Null vorangestellt werden, wenn der Wert kleiner als 10

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

Unterstützt .NET jegliche Zuschreibung (oder ist es mir möglich, ein benutzerdefiniertes Attribut zu erstellen), dass Wird diese Regel erzwingen, möglicherweise unter Verwendung einer Formatzeichenfolge (zB {0:00})?

Hinweis: Ich weiß, dass ich meine eigenen string Eigenschaften hinzufügen könnte, das die Formatierung intern tun, und fügen Sie ein [XmlIgnore] Attribut auf meine int Eigenschaften, aber das fühlt sich an wie eine zweitklassige Lösung.

Bearbeiten: Nach einiger Überlegung frage ich mich, ob dies tatsächlich nicht machbar ist. Serialisierung wäre kein Problem, aber damit die Deserialisierung funktionieren kann, müssen Sie die serialisierte Zeichenfolge wieder formatieren. Im obigen Beispiel wäre das einfach, aber ich bin mir nicht sicher, ob es im allgemeineren Fall funktionieren könnte.

Edit2: Das XML-Schema, das die zweistellige Anforderung definiert, ist unten.

Einfache Typdefinitionen:

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

Kreditkarte Definition, die diese Typen verwendet:

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

Antwort

3

OK, mein vorheriges Codebeispiel ignorieren (Ich werde es überlassen, da es jemand anderes helfen könnte, obwohl). Ich erinnere mich, Sie können diese XmlEnumAttribute mit tun:

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

    ... 

    [XmlEnum("12")] 
    December 
} 

und dann Nutzung der ENUM zu ändern:

public LeadingZeroMonth ValidFromMonth { get; set; } 

Das ist eigentlich eine sehr schöne Art und Weise, da Sie jetzt eine ENUM für den Monat haben (was du eigentlich von Anfang an hättest machen sollen).

+0

Das ist sehr gut - aber ich denke, ich werde noch Sie müssen Ihren LeadingZero-Klassenansatz seit Jahren anwenden. –

+1

Wahrscheinlich. Deshalb habe ich es aufgegeben. Ich dachte, sie wären anders genug, um sie als separate Antworten zu halten (abhängig von Ihren Bedürfnissen). Ich würde wirklich sehen, wie sie das Jahr-Feld zu 4 Ziffern erweitern. Ich meine, komm schon, sie verwenden bereits ein ausführliches Format (XML), wie viel denken sie, dass sie sparen, indem sie nur zwei Ziffern für das Jahr verwenden? Aber ich verstehe, wenn Sie mit ihnen Schema festhalten. So oder so, diese beiden Dinge sollten helfen, das zu erreichen, was Sie brauchen. –

3

Dies ist eine Menge Code, aber es tut, was Sie wollen. Das Wesentliche ist, dass Sie eine neue Klasse (LeadingZero in diesem Beispiel) erstellen und IXmlSerializable implementieren können, um zu steuern, wie Sie aus dem XML-Stream lesen/schreiben. Hoffe, das hilft:

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

Dies ist die Ausgabe, die ich habe:

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

Diese Art der Anforderung kommt häufig von Unternehmen, die XML nicht verstehen. Anstatt anzunehmen, dass dies hier der Fall ist, werde ich fragen: Haben sie Ihnen ein XML-Schema geliefert, das das führende Zero-Day-Format beschreibt? Wenn ja, könnten Sie den Teil des Tages veröffentlichen, der den Tag definiert?


EDIT basierend auf bearbeiten

Vielen Dank für das Schema veröffentlichen. Es bestätigte die andere Sache, um die ich besorgt war. Deine ganzen Zahlen sind keine ganzen Zahlen. Beachten Sie die <restriction base="xs:string"/>. Dies sind Strings, keine ganzen Zahlen.

+0

Ich habe meine Antwort entsprechend aktualisiert –

1

Disadvatage mit XmlEnum ist, dass es nicht

nullable sein kann i

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

dies ermöglicht es Ihnen Recommand wird zuzuschreiben zu machen nullable

+0

Danke für die Informationen - wir haben gerade festgestellt, dass XmlEnum nicht Nullable sein kann, was bedeutet, dass dieser Ansatz nicht mehr für unsere Bedürfnisse geeignet ist. –