Pregunta

Estoy enviando xml a otro programa, que espera indicadores booleanos como " sí " o " no ", en lugar de " true " o " false " ;.

Tengo una clase definida como:

[XmlRoot()]
public class Foo {
    public bool Bar { get; set; }
}

Cuando lo serializo, mi salida se ve así:

<Foo><Bar>true</Bar></Foo>

Pero me gustaría que fuera esto:

<Foo><Bar>yes</Bar></Foo>

¿Puedo hacer esto en el momento de la serialización? Preferiría no tener que recurrir a esto:

[XmlRoot()]
public class Foo {
    [XmlIgnore()]
    public bool Bar { get; set; }

    [XmlElement("Bar")]
    public string BarXml { get { return (Bar) ? "yes" : "no"; } }
}

Tenga en cuenta que también quiero poder deserializar estos datos nuevamente.

¿Fue útil?

Solución

Ok, he estado investigando esto un poco más. Esto es lo que he encontrado:

// use this instead of a bool, and it will serialize to "yes" or "no"
// minimal example, not very robust
public struct YesNo : IXmlSerializable {

    // we're just wrapping a bool
    private bool Value;

    // allow implicit casts to/from bool
    public static implicit operator bool(YesNo yn) {
        return yn.Value;
    }
    public static implicit operator YesNo(bool b) {
        return new YesNo() {Value = b};
    }

    // implement IXmlSerializable
    public XmlSchema GetSchema() { return null; }
    public void ReadXml(XmlReader reader) {
        Value = (reader.ReadElementContentAsString() == "yes");
    }
    public void WriteXml(XmlWriter writer) {
        writer.WriteString((Value) ? "yes" : "no");
    }
}

Luego cambio mi clase de Foo a esto:

[XmlRoot()]
public class Foo {      
    public YesNo Bar { get; set; }
}

Tenga en cuenta que debido a que YesNo se puede convertir implícitamente en bool (y viceversa), aún puede hacer esto:

Foo foo = new Foo() { Bar = true; };
if ( foo.Bar ) {
   // ... etc

En otras palabras, puedes tratarlo como un bool.

Y w00t! Se serializa a esto:

<Foo><Bar>yes</Bar></Foo>

También se deserializa correctamente.

Probablemente haya alguna forma de hacer que mi XmlSerializer lance automáticamente cualquier bool si se encuentra con YesNo s en su funcionamiento, pero aún no lo he encontrado. ¿Alguien?

Otros consejos

Muy simple. Utilice una propiedad sustituta. Aplicar XmlIgnore en la propiedad real. El sustituto es una cadena, y debe usar el atributo XmlElement que toma un reemplazo de nombre de elemento. Especifique el nombre de la propiedad actual en la anulación. La propiedad sustituta se serializa de manera diferente según el valor de la propiedad real. También debe proporcionar un configurador para el Sustituto, y el establecedor debe establecer la propiedad real de manera apropiada, independientemente del valor que haya serializado. En otras palabras, tiene que ir en ambos sentidos.

Recorte:

    public class SomeType 
    {

        [XmlElement]
        public int IntValue;

        [XmlIgnore]
        public bool Value;

        [XmlElement("Value")]
        public string Value_Surrogate {
            get { return (Value)? "Yes, definitely!":"Absolutely NOT!"; }
            set { Value= (value=="Yes, definitely!"); }
        }

    }

haga clic aquí para ejemplo de fuente compilable completo .

Haciendo que un valor bool se serialice como " yes " o " no " cambia el tipo de datos de ser un booleano en absoluto. En su lugar, ¿puede agregar una propiedad separada que evalúe un valor booleano y devuelva " sí " o " no " Como es apropiado para su tipo de datos? Quizás incluso puedas forzar " sí " o " no " al hacer que el tipo de retorno sea una enumeración que solo especifica esos valores.

public YesOrNo DoYouLoveIt
{
    get { return boolToEvaluate ? YesOrNo.Yes : YesOrNo.No; }
}

Eso podría ser una exageración, pero podría responder a su necesidad. La única razón por la que menciono una enumeración para un valor tan simple es que restringiría los valores en lugar de permitir cualquier cadena.

Utilizo el método de propiedad, pero en lugar de verificar si la cadena es igual a sí o no, prefiero verificar si la cadena comienza con (no distingue mayúsculas) " YT1 " ;. Esto permite que el archivo contenga verdadero, verdadero, t, T, y, Y, sí, sí, 1, etc., todo lo que se evaluará como verdadero. Si bien puedo especificar que falso es falso, falso, f, F, n, N, no, No, 0, etc., todo lo que no coincida con el verdadero se evalúa como falso.

El ejemplo de su propiedad es probablemente la forma más sencilla de hacerlo. Si ayuda, creo que no es necesario que sea una propiedad pública, ya que el atributo implementa ISerializable en la clase detrás de su espalda. Para habilitar la deserialización, deberías poder implementar el set {Bar = value == " yes " ;; }

@Blorgbeard: Si tiene más de una de estas clases YesNo en una clase de objeto, Asegúrate de leer todo el elemento.

public void ReadXml(XmlReader reader)
{
    string element = reader.ReadOuterXml();
    int startIndex = element.IndexOf('>') + 1;
    int length = element.LastIndexOf('<') - startIndex;

    string text = (element.Substring(startIndex, length).ToLowerInvariant();

    Value = (text == "yes");
}

De lo contrario, esto podría causar problemas.

  

El método ReadXml debe reconstituir su objeto utilizando la información que fue escrita por el método WriteXml.

     

Cuando se llama a este método, el lector se coloca al comienzo del elemento que envuelve la información para su tipo. Es decir, solo   antes de la etiqueta de inicio que indica el comienzo de un serializado   objeto. Cuando este método vuelve, debe haber leído todo el elemento.   De principio a fin, incluyendo todos sus contenidos. A diferencia del   Método WriteXml, el marco no maneja el elemento contenedor   automáticamente. Su implementación debe hacerlo. No observar   Estas reglas de posicionamiento pueden hacer que el código genere un tiempo de ejecución inesperado.   Excepciones o datos corruptos.

Lo que necesitas hacer parece más bien un problema de visualización. Si su aplicación lo permite, será mejor que mantenga el tipo de datos como booleano y muestre Sí / No en su interfaz de usuario.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top