2010-06-03 20 views
15

Intentando deserializar algunos snippits xml de un proveedor en objetos. El problema es que estoy obteniendo un formato no válido en cada etiqueta de elemento empy. Puedo deserializar el objeto sin problemas cuando todos los elementos tienen valores. O los elementos vacíos están omitidos.Deserializar Xml con elementos vacíos en C#

Xml snippit:

<foo>
<PROPONE/PROPONE>
< propTwo/>
</foo >

C# Clase:

[Serialilbe()]  
public class foo 
{ 
    public foo(){} 
    [XmlElementAttribute(IsNullable = true)] 
    public int? propOne {get;set;} 
    [XmlElementAttribute(IsNullable = true)] 
    public int? propTwo {get;set;} 
} 

¿Hay alguna configuración en la clase que pueda realizar para ajustar el análisis sintáctico?
o
¿Hay alguna manera fácil de aplicar xsl para eliminar estos elementos?
o
¿Debo usar regEx para eliminar los elementos vacíos antes de la destrucción?
o
una forma aún mejor?

+0

¿Está números de serie a través de la misma interfaz (POR EJEMPLO clase XmlSerializer)? –

+0

Como nota al margen, el XMLSerializer está próximo a quedar obsoleto.Puede considerar usar DataContractSerializer. –

Respuesta

10

La manera más uniforme de limpiar estos nodos parece ser agregar un filtro RegEx al deserializador.

public static T Deserialize<T>(string xml){ 
     XmlSerializer xs = new XmlSerializer(typeof(T)); 
     string cleanXml = Regex.Replace(xml, @"<[a-zA-Z].[^(><.)]+/>", 
             new MatchEvaluator(RemoveText)); 
     MemoryStream memoryStream = new MemoryStream((new UTF8Encoding()).GetBytes(cleanXml)); 
     XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8); 
     return (T)xs.Deserialize(memoryStream); 
    } 
static string RemoveText(Match m) { return "";} 
+1

¿Qué pasa si hay un elemento completo sin un valor: ''. Escribí mi propia lógica para eliminar esto, pero es demasiado lento y el archivo demasiado grande. ¿Podemos escribir RegEx para detectar esto? – MrFox

9

Ver este artículo: Can XmlSerializer deserialize into a Nullable?

En pocas palabras el código XML debe ser similar a esto si desea utilizar tipos anulables:

<foo xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'> 
<propOne>1</propOne> 
<propTwo xsi:nil='true'/> 
</foo> 

Los dos cambios están agregando el espacio de nombres, y explícitamente el establecimiento de xsi : nil a verdadero en el elemento nulo.

Si usted no tiene control sobre el código XML no es una técnica más avanzada se describe aquí: Using XmlSerializer to deserialize into a Nullable

+0

El enlace "Usar XmlSerializer para deserializar en un Nullable" está muerto. Una forma de hacerlo es implementar IXmlSerializable y convertir empty a null dentro de ReadXml(). Similar a http://stackoverflow.com/a/625463/1034683 – bodhizero

0

Para simplificar, ¿por qué no analizar el código XML explicitamente usando XmlDocument y XPath? Use XPath para acceder explícitamente a cada nodo xml, p.

XmlNode node = xml.SelectSingleNode ("foo/PropOne"); 
if (node != null) 
{ 
    propOneValue = node.innerText; 
} 
+1

Supongo que quiere deserializar en una clase/tipo y no tener que extraer los valores uno por uno. – user1040975

8

Otra opción si no tiene control sobre el XML de entrada es para evitar este haciendo que el deserializer pretender que la variable es una cadena:

[Serializable()]  
public class foo 
{ 
    public foo(){} 

    [XmlElement("propOne")] 
    [EditorBrowsable(EditorBrowsableState.Never)] 
    public string propOneString {get;set;} 

    [XmlIgnore] 
    private int? propOneInternal = null; 
    [XmlIgnore] 
    private bool propOneSet = false; 

    [XmlIgnore] 
    public int? propOne 
    { 
    get 
    { 
     if (!propOneSet) 
     { 
     if(!string.IsNullOrEmpty(propOneString) 
     { 
      propOneInternal = int.Parse(propOneString); 
     } 
     //else leave as pre-set default: null 
     propOneSet = true; 
     } 
     return propOneInternal; 
    } 
    set { propOneInternal = value; } 
    } 
} 

El Deserialiser se complace en analizar un elemento de cadena cuando está vacío, por lo que puede utilizarlo.

No es particularmente agradable, pero servirá si sólo tienes uno o 2 etiquetas para cubrir

+0

EDITAR: propOneString obviamente debe ser una cadena, no una int :) – Brondahl

+0

Sí, la manera más fácil para mí. Solo tenía una etiqueta para tratar. ¡Gracias! – GibralterTop

Cuestiones relacionadas