Сериализация .Net объекта в json, управляемая с помощью атрибутов xml - PullRequest
14 голосов
/ 14 января 2011

У меня есть объект .Net, который я сериализовал в Xml и который украшен атрибутами Xml. Теперь я хотел бы сериализовать тот же объект в Json, предпочтительно используя библиотеку Newtonsoft Json.Net .

Я бы хотел перейти непосредственно от объекта .Net в памяти к строке Json (без предварительной сериализации в Xml). Я не хочу добавлять какие-либо атрибуты Json в класс, но вместо этого хотел бы, чтобы сериализатор Json использовал существующие атрибуты Xml.

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

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

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

становится

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

Ответы [ 4 ]

10 голосов
/ 14 января 2011

Используйте [JsonProperty(PropertyName="foo")] Атрибут и установите PropertyName.

5 голосов
/ 27 января 2011

Оказывается, что это не существовало в библиотеке Newtonsoft Json.Net.Я написал патч и загрузил его в систему отслеживания проблем Json.Net (архивная ссылка здесь ):

Это позволяет выполнять следующие действия:

  • XmlIgnore работает точно так же, как JsonIgnore.
  • XmlElementAttribute.ElementName изменит имя свойства Json.
  • XmlType.AnonymousType запретит печатать объекты в Json (свойство XmlContractResolnyTySinter для Jsonэто поведение) это немного глупо, так как мне приходилось изучать внутренности Json.Net по ходу дела.
4 голосов
/ 22 ноября 2017

Вы можете создать собственный распознаватель контракта, который позволит вам вносить изменения в свойства и настраивать их на игнорирование места установки XmlIgnoreAttribute.

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

Вы можете использовать этот настраиваемый распознаватель, установивContractResolver свойство JsonSerializerSettings при сериализации объекта

https://www.newtonsoft.com/json/help/html/ContractResolver.htm

string json =
    JsonConvert.SerializeObject(
        product, // this is your object that has xml attributes on it that you want ignored
        Formatting.Indented,
        new JsonSerializerSettings { ContractResolver = new CustomResolver() }
        );

Если вы используете WebApi, вы можете установить его глобально для применения ко всем контрактам.

var config = GlobalConfiguration.Configuration;
var jsonSettings = config.Formatters.JsonFormatter.SerializerSettings;
jsonSettings.ContractResolver = new CustomContractResolver();
0 голосов
/ 08 июня 2017

Класс ниже можно использовать для сериализации (и десериализации) частей дерева объектов в XML, а затем в JSON.

Использование

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

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

JsonXmlConverter class

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