2009-07-20 6 views
12

Ho riscontrato un problema con la deserializzazione di un file XML con valori booleani. I file XML di origine che sto deserializzando sono stati creati da un'app VB6, in cui tutti i valori booleani sono in maiuscolo (True, False). Quando cerco di deserializzare il XML, sto diventando unSerializzazione Xml vs. "True" e "False"

System.FormatException: The string 'False' is not a valid Boolean value. 

C'è un modo per dire ignorare caso con un attributo?

risposta

5

Si può leggere quel valore come una stringa in un campo stringa, quindi avere un campo bool di sola lettura che contiene un'istruzione if per restituire bool vero o falso.

Per esempio (utilizzando C#):

public bool str2bool(string str) 
{ 
    if (str.Trim().ToUpper() == "TRUE") 
     return true; 
    else 
     return false; 
} 

E si può utilizzare nel modello:

<xsl:if test="user:str2bool($mystr)"> 
+1

Dovresti includere un esempio di questo. Probabilmente hai il miglior suggerimento se lo fai. –

1

Non penso ci sia. È possibile creare una stringa e fare un confronto (String.Compare) impostando il valore ignoreCase su true.

3

Non c'è. Serializer XML funziona con XML Schema e "True" e "False" non sono booleane validi.

È possibile utilizzare una Trasformazione XML per convertire questi due valori oppure è possibile implementare l'interfaccia IXmlSerializable ed effettuare la serializzazione e la deserializzazione da soli.

+0

hai ragione John, questo è quello che succede quando rispondi prima di pranzare: \ .. ma per essere onesti, il tuo suggerimento di Xml Transform potrebbe anche trasformare un valore che non vuole essere un booleano. –

+0

In realtà, no. Vorrei che si riferisse esplicitamente solo agli attributi e/o agli elementi che sono booleani. Non intendevo trasformare ogni attributo. –

+0

Capito John. –

5

Invece di usare Vero o Falso, utilizzare 0 o 1. Si lavorerà per booleano.

4

Sulla base another stack overflow question si può fare:

public class MySerilizedObject 
{ 
    [XmlIgnore] 
    public bool BadBoolField { get; set; } 

    [XmlElement("BadBoolField")] 
    public string BadBoolFieldSerialize 
    { 
     get { return this.BadBoolField ? "True" : "False"; } 
     set 
     { 
      if(value.Equals("True")) 
       this.BadBoolField = true; 
      else if(value.Equals("False")) 
       this.BadBoolField = false; 
      else 
       this.BadBoolField = XmlConvert.ToBoolean(value); 
     } 
    } 
} 
0

mi sono imbattuto lo stesso problema, e sulla base della risposta da jman, ho risolto in questo modo:

[XmlIgnore] 
    public bool BadBoolField { get; set; } 

    [XmlAttribute("badBoolField")] 
    public string BadBoolFieldSerializable 
    { 
     get 
     { 
      return this.BadBoolField.ToString(); 
     } 
     set 
     { 
      this.BadBoolField= Convert.ToBoolean(value); 
     } 
    } 

essere a conoscenza questo è non necessariamente dalla specifica XML/Serialization, ma funziona bene e può gestire valori di conversione molto diffusi (cioè stringhe come "True", "true", se si sostituisce il vincolo di essere una stringa che potrebbe gestire anche i numeri).

0

Ecco una soluzione molto più pulita che mi è venuta in mente in base ad altre domande che ho trovato. E 'molto più pulito, perché allora non c'è bisogno di qualsiasi cosa nel codice, tranne dichiarare il tipo di SafeBool, in questo modo:

public class MyXMLClass 
{ 
    public SafeBool Bool { get; set; } 
    public SafeBool? OptionalBool { get; set; } 
} 

si può anche renderli opzionali e tutto funziona. Questa struttura di SafeBool gestirà tutte le varianti di case di vero/falso, sì/no o y/n. Verrà sempre serializzato come vero/falso, tuttavia ho altre strutture simili a questo che uso per serializzare specificamente come y/n o sì/no quando lo schema lo richiede (es .: strutture BoolYN, BoolYesNo).

using System.Xml; 
using System.Xml.Schema; 
using System.Xml.Serialization; 

namespace AMain.CommonScaffold 
{ 
    public struct SafeBool : IXmlSerializable 
    { 
     private bool _value; 

     /// <summary> 
     /// Allow implicit cast to a real bool 
     /// </summary> 
     /// <param name="yn">Value to cast to bool</param> 
     public static implicit operator bool(
      SafeBool yn) 
     { 
      return yn._value; 
     } 

     /// <summary> 
     /// Allow implicit cast from a real bool 
     /// </summary> 
     /// <param name="b">Value to cash to y/n</param> 
     public static implicit operator SafeBool(
      bool b) 
     { 
      return new SafeBool { _value = b }; 
     } 

     /// <summary> 
     /// This is not used 
     /// </summary> 
     public XmlSchema GetSchema() 
     { 
      return null; 
     } 

     /// <summary> 
     /// Reads a value from XML 
     /// </summary> 
     /// <param name="reader">XML reader to read</param> 
     public void ReadXml(
      XmlReader reader) 
     { 
      var s = reader.ReadElementContentAsString().ToLowerInvariant(); 
      _value = s == "true" || s == "yes" || s == "y"; 
     } 

     /// <summary> 
     /// Writes the value to XML 
     /// </summary> 
     /// <param name="writer">XML writer to write to</param> 
     public void WriteXml(
      XmlWriter writer) 
     { 
      writer.WriteString(_value ? "true" : "false"); 
     } 
    } 
} 
+0

Vedere la mia ricerca e sostituire la risposta. Hai un sacco di codice che potrebbe avere O (n) migliore, ma a volte il problema richiede solo una soluzione Ross Perot. apri il cofano e aggiustalo. –

-1

Non preoccuparti di riparare un sistema xml danneggiato o di combattere XmlSerializer, soprattutto per qualcosa di così banale. Non ne vale la pena. VB6 non tornerà presto.

Invece, afferrare il documento prima che sia deserializzato e modificare i valori. Se sei preoccupato di cambiarli al di fuori dei tag, usa espressioni regolari o includi le parentesi angolari nei valori.

xml = xml.Replace("True", "true").Replace("False", "false"); 

Non vincerà nessun premio per l'eleganza, ma ti farà tornare al lavoro. A volte devi solo metterlo a posto.

Per quanto riguarda le prestazioni, sì, si sta reiterando attraverso la stringa O (n), ma poiché le stringhe di sostituzione sono della stessa lunghezza, non richiede alcun elemento di stringa mobile attorno. Inoltre, a seconda dell'implementazione, potrebbe esserci un overhead maggiore nella modifica di XmlSerializer.

+0

Si presume che si abbia un facile accesso al codice HTML originale per poter effettuare una ricerca e sostituirla, quindi la risposta non è buona. Per non parlare del fatto che se il pacchetto XML è grande, il codice produrrà una stringa temporanea enorme due volte, perché le stringhe in .net sono immutabili. –

+0

@KendallBennett Beh, non stai anche assumendo che abbia accesso alle classi? Non ho mai visto un caso in cui è possibile deserializzare i dati senza avere accesso all'input xml. Se sei davvero preoccupato per le prestazioni e la memoria, dovresti davvero evitare di utilizzare XmlSerializer poiché utilizza la reflection, che è una delle operazioni più costose in .NET. Non c'è niente nella mia soluzione che dice che non può funzionare sullo streaming dei dati. Il mio punto è che le implementazioni ingenue a volte sono le migliori. L'ho imparato in questo modo. –

+0

Non è possibile semplicemente bloccare la sostituzione di tutto nell'XML che è True con true e False con false. È certamente ingenuo e certamente andando a rompere su un certo tipo di risposte. E se ci fosse qualcosa di memorizzato in quel caso che fosse sensibile al maiuscolo/minuscolo e avesse la parola Vero in esso? Improvvisamente non funziona più ... –