Skip to content

Latest commit

 

History

History
275 lines (242 loc) · 8.49 KB

CustomJsonReader.md

File metadata and controls

275 lines (242 loc) · 8.49 KB

Custom JsonReader

This sample creates a custom Argon.JsonReader.

public class XmlJsonReader(XmlReader reader) : JsonReader
{
    readonly Stack<JTokenType> stateStack = new();

    JTokenType? valueType;

    JTokenType PeekState()
    {
        var current = stateStack.Count > 0 ? stateStack.Peek() : JTokenType.None;
        return current;
    }

    public override bool Read()
    {
        if (HandleValueType())
        {
            return true;
        }

        while (reader.Read())
        {
            switch (reader.NodeType)
            {
                case XmlNodeType.Element:
                    var typeName = reader.GetAttribute("type");
                    if (typeName == null)
                    {
                        throw new("No type specified.");
                    }

                    valueType = (JTokenType) Enum.Parse(typeof(JTokenType), typeName, true);

                    switch (PeekState())
                    {
                        case JTokenType.None:
                            HandleValueType();
                            return true;
                        case JTokenType.Object:
                            SetToken(JsonToken.PropertyName, reader.LocalName);
                            stateStack.Push(JTokenType.Property);
                            return true;
                        case JTokenType.Array:
                            continue;
                        default:
                            throw new ArgumentOutOfRangeException();
                    }
                case XmlNodeType.EndElement:
                    switch (stateStack.Peek())
                    {
                        case JTokenType.Object:
                            SetToken(JsonToken.EndObject);
                            stateStack.Pop();
                            if (PeekState() == JTokenType.Property)
                            {
                                stateStack.Pop();
                            }

                            return true;
                        case JTokenType.Array:
                            SetToken(JsonToken.EndArray);
                            stateStack.Pop();
                            if (PeekState() == JTokenType.Property)
                            {
                                stateStack.Pop();
                            }

                            return true;
                    }

                    stateStack.Pop();
                    if (PeekState() == JTokenType.Property)
                    {
                        stateStack.Pop();
                    }

                    break;
                case XmlNodeType.Text:
                case XmlNodeType.CDATA:
                    switch (valueType)
                    {
                        case JTokenType.Integer:
                            SetToken(JsonToken.Integer, Convert.ToInt64(reader.Value, InvariantCulture));
                            break;
                        case JTokenType.Float:
                            SetToken(JsonToken.Float, Convert.ToDouble(reader.Value, InvariantCulture));
                            break;
                        case JTokenType.String:
                        case JTokenType.Uri:
                        case JTokenType.TimeSpan:
                        case JTokenType.Guid:
                            SetToken(JsonToken.String, reader.Value);
                            break;
                        case JTokenType.Boolean:
                            SetToken(JsonToken.Boolean, Convert.ToBoolean(reader.Value, InvariantCulture));
                            break;
                        case JTokenType.Date:
                            SetToken(JsonToken.Date, Convert.ToDateTime(reader.Value, InvariantCulture));
                            break;
                        case JTokenType.Bytes:
                            SetToken(JsonToken.Bytes, Convert.FromBase64String(reader.Value));
                            break;
                        default:
                            throw new ArgumentOutOfRangeException();
                    }

                    stateStack.Push(valueType.Value);
                    return true;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }

        return false;
    }

    bool HandleValueType()
    {
        switch (valueType)
        {
            case JTokenType.Null:
                SetToken(JsonToken.Null);
                valueType = null;

                if (PeekState() == JTokenType.Property)
                {
                    stateStack.Pop();
                }

                return true;
            case JTokenType.Object:
                SetToken(JsonToken.StartObject);
                stateStack.Push(JTokenType.Object);
                valueType = null;
                return true;
            case JTokenType.Array:
                SetToken(JsonToken.StartArray);
                stateStack.Push(JTokenType.Array);
                valueType = null;
                return true;
        }

        return false;
    }

    public override int? ReadAsInt32()
    {
        if (Read())
        {
            return Value == null ? null : Convert.ToInt32(Value);
        }

        return null;
    }

    public override string ReadAsString()
    {
        if (Read())
        {
            return (string) Value;
        }

        return null;
    }

    public override byte[] ReadAsBytes()
    {
        if (Read())
        {
            return (byte[]) Value;
        }

        return null;
    }

    public override decimal? ReadAsDecimal()
    {
        if (Read())
        {
            return Value == null ? null : Convert.ToDecimal(Value);
        }

        return null;
    }

    public override DateTime? ReadAsDateTime()
    {
        if (Read())
        {
            return Value == null ? null : Convert.ToDateTime(Value);
        }

        return null;
    }

    public override DateTimeOffset? ReadAsDateTimeOffset()
    {
        if (Read())
        {
            return Value == null ? null : Convert.ToDateTime(Value);
        }

        return null;
    }
}

snippet source | anchor

var xml = """
          <Root type="Object">
            <Null type="Null" />
            <String type="String">This is a string!</String>
            <Char type="String">!</Char>
            <Integer type="Integer">123</Integer>
            <DateTime type="Date">2001-02-22T20:59:59Z</DateTime>
            <DateTimeOffset type="Date">2001-02-22T20:59:59+12:00</DateTimeOffset>
            <Float type="Float">1.1</Float>
            <Double type="Float">3.14</Double>
            <Decimal type="Float">19.95</Decimal>
            <Guid type="Guid">d66eab59-3715-4b35-9e06-fa61c1216eaa</Guid>
            <Uri type="Uri">http://james.newtonking.com</Uri>
            <Array type="Array">
              <Item type="Integer">1</Item>
              <Item type="Bytes">SGVsbG8gd29ybGQh</Item>
              <Item type="Boolean">True</Item>
            </Array>
            <Object type="Object">
              <String type="String">This is a string!</String>
              <Null type="Null" />
            </Object>
          </Root>
          """;

var sr = new StringReader(xml);

using (var xmlReader = XmlReader.Create(sr, new() {IgnoreWhitespace = true}))
using (var reader = new XmlJsonReader(xmlReader))
{
    var o = JObject.Load(reader);
    //{
    //  "Null": null,
    //  "String": "This is a string!",
    //  "Char": "!",
    //  "Integer": 123,
    //  "DateTime": "2001-02-23T09:59:59+13:00",
    //  "DateTimeOffset": "2001-02-22T21:59:59+13:00",
    //  "Float": 1.1,
    //  "Double": 3.14,
    //  "Decimal": 19.95,
    //  "Guid": "d66eab59-3715-4b35-9e06-fa61c1216eaa",
    //  "Uri": "http://james.newtonking.com",
    //  "Array": [
    //    1,
    //    "SGVsbG8gd29ybGQh",
    //    true
    //  ],
    //  "Object": {
    //    "String": "This is a string!",
    //    "Null": null
    //  }
    //}
}

snippet source | anchor