2011-01-14 14 views
13

Tengo un objeto .Net que he estado serializando en Xml y está decorado con atributos Xml. Ahora me gustaría serializar el mismo objeto a Json, de preferencia usando la biblioteca Newtonsoft Json.Net.Serializar objeto .Net a json, controlado mediante atributos xml

Me gustaría ir directamente desde el objeto .Net en la memoria a una cadena Json (sin serializar primero a Xml). No deseo agregar ningún atributo Json a la clase, pero en cambio me gustaría que el serializador Json use los atributos Xml existentes.

public class world{ 
    [XmlIgnore] 
    public int ignoreMe{ get; } 

    [XmlElement("foo")] 
    public int bar{ get; } 

    [XmlElement("marco")] 
    public int polo{ get; } 
} 

convierte

{ 
    "foo":0, 
    "marco":0 
} 
+0

Newtonsoft Json.Net http://james.newtonking.com/projects/json/help/SerializationAttributes.html "también busca la DataContract y atributos DataMember la hora de determinar la forma en JSON es que ser serializado y deserializado". ¿Alguien sabe si XmlElementAttributes et al son interoperables con DataContractAttributes? –

+0

Un serializador podría implementar la serialización de ambos Atributos, pero supongo que depende del serializador ... (también vea http://social.msdn.microsoft.com/Forums/en/wcf/thread/be796bd0-2502-4bd3- 96d9-60bf7d68930d) – hangy

+0

He escrito un pequeño parche para Json.Net que permite que DefaultContractResolver funcione con atributos Xml. Funciona para el ejemplo simple anterior, pero necesito escribir algunas pruebas más para ejemplos más complejos (tipo anónimo, etc.) antes de liberarlo. –

Respuesta

4

Resulta que esta no era una característica existente de la biblioteca Newtonsoft Json.Net. He escrito un parche y subido a la Json.Net issue tracker

Esto permite lo siguiente:

  • XmlIgnore funciona igual que JsonIgnore.
  • XmlElementAttribute.ElementName alterará el nombre de la propiedad Json.
  • XmlType.AnonymousType suprimirá la impresión de objetos en Json (propiedad XmlContractResolver.SuppressAnonymousType altera este comportamiento) esto es un poco hacky, ya que he tenido que aprender las partes internas de Json.Net como he estado yendo.
+8

Por si acaso alguien se encuentra con esto, no lo convirtió en el origen de Json.NET. Estaría muy interesado en conocer otras soluciones. – Martin

+0

Personalmente, me gusta la idea de agregar eligiendo qué serializador quieres usar, y también, potencialmente, en qué orden (como James mencionó en el número). –

11

Uso [JsonProperty(PropertyName="foo")] atributo y establezca la PropertyName.

+0

Lamentablemente, esto no responde la pregunta. Soy reacio a agregar más atributos a mis POCO: tengo cientos de ellos con miles de propiedades y deseo alejarme de una solución donde tengo dos lugares para modificar si cambia el nombre de una propiedad. –

+0

OK, actualice la pregunta con este requisito suyo para que la gente pueda contribuir.Por cierto, obtuve un voto negativo, ¿eras tú? – Aliostad

+0

Esto es hace un par de meses, pero si está preocupado por sobre decorar su POCOS, ¿por qué no utilizar un modelo de vista para sus atributos json? Uso esto y mi POCOS me mantengo agradable y limpio. – trevorc

0

La siguiente clase se puede utilizar para serializar (y deserializar) partes del árbol de objetos en XML y luego en JSON.

Uso

[JsonObject] 
public class ClassToSerializeWithJson 
{ 
    [JsonProperty] 
    public TypeThatIsJsonSerializable PropertySerializedWithJsonSerializer {get; set; } 

    [JsonProperty] 
    [JsonConverter(typeof(JsonXmlConverter<TypeThatIsXmlSerializable>))] 
    public TypeThatIsXmlSerializable PropertySerializedWithCustomSerializer {get; set; } 
} 

clase JsonXmlConverter

public class JsonXmlConverter<TType> : JsonConverter where TType : class 
{ 
    private static readonly XmlSerializer xmlSerializer = new XmlSerializer(typeof(TType)); 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     var xml = ToXml(value as TType); 
     using (var stream = new StringReader(xml)) 
     { 
      var xDoc = XDocument.Load(stream); 
      var json = JsonConvert.SerializeXNode(xDoc); 
      writer.WriteRawValue(json); 
     } 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     if (reader.TokenType == JsonToken.Null) 
     { 
      // consume the 'null' token to set the reader in the correct state 
      JToken.Load(reader); 
      return null; 
     } 
     var jObj = JObject.Load(reader); 
     var json = jObj.ToString(); 
     var xDoc = JsonConvert.DeserializeXNode(json); 
     var xml = xDoc.ToString(); 
     return FromXml(xml); 
    } 

    public override bool CanRead => true; 

    public override bool CanConvert(Type objectType) => objectType == typeof(TType); 

    private static TType FromXml(string xmlString) 
    { 
     using (StringReader reader = new StringReader(xmlString)) 
      return (TType)xmlSerializer.Deserialize(reader); 
    } 

    private static string ToXml(TType obj) 
    { 
     using (StringWriter writer = new StringWriter()) 
     using (XmlWriter xmlWriter = XmlWriter.Create(writer)) 
     { 
      XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); 
      ns.Add(String.Empty, String.Empty); 

      xmlSerializer.Serialize(xmlWriter, obj, ns); 
      return writer.ToString(); 
     } 
    } 
} 
2

Se puede crear un dispositivo de resolución de contrato de encargo que le permitirá hacer los ajustes para las propiedades y los puso a hacer caso donde un XmlIgnoreAttribute Está establecido.

public class CustomContractResolver : DefaultContractResolver 
{ 
    private readonly JsonMediaTypeFormatter formatter; 

    public CustomContractResolver(JsonMediaTypeFormatter formatter) 
    { 
     this.formatter = formatter; 
    } 

    public JsonMediaTypeFormatter Formatter 
    { 
     [DebuggerStepThrough] 
     get { return this.formatter; } 
    } 

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) 
    { 
     JsonProperty property = base.CreateProperty(member, memberSerialization); 
     this.ConfigureProperty(member, property); 
     return property; 
    } 

    private void ConfigureProperty(MemberInfo member, JsonProperty property) 
    { 
     if (Attribute.IsDefined(member, typeof(XmlIgnoreAttribute), true)) 
     { 
      property.Ignored = true; 
     }    
    } 
} 
Cuestiones relacionadas