Json.net을 사용하여 JSON 구문 분석


111

JSon.Net 라이브러리를 사용하여 일부 JSON을 구문 분석하려고합니다. 문서가 약간 드물게 보이며 필요한 작업을 수행하는 방법에 대해 혼란 스럽습니다. 다음은 구문 분석해야하는 JSON 형식입니다.

{
    "displayFieldName" : "OBJECT_NAME", 
    "fieldAliases" : {
        "OBJECT_NAME" : "OBJECT_NAME", 
        "OBJECT_TYPE" : "OBJECT_TYPE"
    }, 
    "positionType" : "point", 
    "reference" : {
        "id" : 1111
    }, 
    "objects" : [ {
        "attributes" : {
            "OBJECT_NAME" : "test name", 
            "OBJECT_TYPE" : "test type"
        }, 
        "position" : {
            "x" : 5, 
            "y" : 7
        }
    } ]
}

이것에서 정말로 필요한 유일한 데이터는 객체 배열의 항목입니다. JSonTextReader와 같은 것으로 구문 분석하고 OBJECT_TYPE 및 x 및 y 위치와 같은 원하는 것을 끌어낼 수 있습니까? JSonTextReader원하는 방식으로 작업 할 수없는 것 같고 사용 사례가 거의 또는 전혀 없습니다.

먼저 직렬화 한 다음 내 개체와 함께 LINQ를 사용하는 것이 이상적이며 찾은 모든 예제에서 JSON 직렬화를 먼저 논의하지만이 구조에 대한 개체를 어떻게 빌드할지 모르겠습니다. 특히 속성 및 위치 개체 쌍의 목록과 같은 것이어야하는 개체 배열입니다. JSon.Net이 그것을 직렬화하는 방법을 알 수 있도록 내 개체를 어떻게 코딩할지 모르겠습니다.

필요한 모든 것을 내가 만든 속성 객체로 끌어 내기 위해 간단한 파서를 작성할 수 있다고 생각했지만 운이 거의 없습니다.

이 모든 것이 이해되기를 바랍니다. 어떤 아이디어라도 있습니까?

답변:


129

JSON.NET에 대해 모르지만 (.NET 3.5 SP1) JavaScriptSerializer에서 잘 작동합니다 System.Web.Extensions.dll.

using System.Collections.Generic;
using System.Web.Script.Serialization;
public class NameTypePair
{
    public string OBJECT_NAME { get; set; }
    public string OBJECT_TYPE { get; set; }
}
public enum PositionType { none, point }
public class Ref
{
    public int id { get; set; }
}
public class SubObject
{
    public NameTypePair attributes { get; set; }
    public Position position { get; set; }
}
public class Position
{
    public int x { get; set; }
    public int y { get; set; }
}
public class Foo
{
    public Foo() { objects = new List<SubObject>(); }
    public string displayFieldName { get; set; }
    public NameTypePair fieldAliases { get; set; }
    public PositionType positionType { get; set; }
    public Ref reference { get; set; }
    public List<SubObject> objects { get; set; }
}
static class Program
{

    const string json = @"{
  ""displayFieldName"" : ""OBJECT_NAME"", 
  ""fieldAliases"" : {
    ""OBJECT_NAME"" : ""OBJECT_NAME"", 
    ""OBJECT_TYPE"" : ""OBJECT_TYPE""
  }, 
  ""positionType"" : ""point"", 
  ""reference"" : {
    ""id"" : 1111
  }, 
  ""objects"" : [
    {
      ""attributes"" : {
        ""OBJECT_NAME"" : ""test name"", 
        ""OBJECT_TYPE"" : ""test type""
      }, 
      ""position"" : 
      {
        ""x"" : 5, 
        ""y"" : 7
      }
    }
  ]
}";


    static void Main()
    {
        JavaScriptSerializer ser = new JavaScriptSerializer();
        Foo foo = ser.Deserialize<Foo>(json);
    }


}

편집하다:

Json.NET은 동일한 JSON 및 클래스를 사용하여 작동합니다.

Foo foo = JsonConvert.DeserializeObject<Foo>(json);

링크 : Json.NET으로 JSON 직렬화 및 역 직렬화


13
특정 / 사용자 정의 클래스를 만들 필요가 없도록 JSON 문자열의 이름 값 쌍을 기존 C # 변수 유형 (예 : 배열 또는 사전?)으로 변환하는 방법이 있습니까? 제 경우에는 JSON 문자열이 Ruby / Rails에서 생성됩니다 ...
Greg

1
역 직렬화 할 클래스를 빌드 할 필요가 없습니다 XElement. JSON 개체에서 LINQ를 사용할 수 있는 것과 동등한 것이 있습니까?
GraemeF 2011 년

@Marc Gravell : 감사합니다! 나는 JSon에 대해 아무것도 몰랐다. 그러나이 예제를 통해 애플리케이션에 대한 구성 파일 (계층 구조 포함)을 쉽게 만들 수있었습니다.
Peter17 2011-04-07

1
@ Peter17 : 구성에 JSON을 사용하면 안됩니다. .NET 프레임 워크에는 구성 파일의 계층 적 구성 섹션을 허용하는 인프라가 있습니다. 사용자 지정 솔루션을 사용하면 사람들은 이제 .config 파일 사용자 지정 구성 섹션에 대해 걱정해야합니다 .
casperOne

1
내부 "Object_name"및 "Object_Type", 즉 ""test name ""및 ""test type ""에서 값을 가져 오는 방법은 무엇입니까? 이에 대한 솔루션을 편집 해 주시겠습니까?
AskMe 2015-07-21

10

편집 : 감사합니다 Marc, struct vs class 문제에 대해 읽으 십시오. 맞습니다. 감사합니다!

JSon.Net의 정적 방법을 사용하여 설명하는 작업을 수행하기 위해 다음 방법을 사용하는 경향이 있습니다.

MyObject deserializedObject = JsonConvert.DeserializeObject<MyObject>(json);

링크 : Json.NET으로 JSON 직렬화 및 역 직렬화

객체 목록의 경우 attributesposition클래스를 포함하는 자신의 작은 클래스로 만든 일반 목록을 사용하는 것이 좋습니다 . X와 Y를 위해 ( 또는 부동 소수점 숫자에) Point구조체를 사용할 수 있습니다 .System.DrawingSystem.Drawing.PointSystem.Drawing.PointF

객체 생성 후에는 다른 방식으로보고있는 텍스트 구문 분석보다 원하는 데이터를 얻는 것이 훨씬 쉽습니다.


구조체는 여기서 (만약 있다면) 좋은 선택이 될 수 없습니다. 객체 (클래스)에 충실합니다.
Marc Gravell

3

(이 질문은 검색 엔진 결과에서 높았지만 결국 다른 접근 방식을 사용했습니다. 비슷한 질문을 가진 다른 사람들이 이것을 읽을 경우이 오래된 질문에 대한 답변을 추가)

Json.Net으로이 문제를 해결하고 반복하려는 항목을 처리하는 확장 메서드를 만들 수 있습니다.

public static Tuple<string, int, int> ToTuple(this JToken token)
{
    var type = token["attributes"]["OBJECT_TYPE"].ToString();
    var x = token["position"]["x"].Value<int>();
    var y = token["position"]["y"].Value<int>();
    return new Tuple<string, int, int>(type, x, y);
}

그리고 다음과 같은 데이터에 액세스합니다. (시나리오 : 콘솔에 쓰기) :

var tuples = JObject.Parse(myJsonString)["objects"].Select(item => item.ToTuple()).ToList();
tuples.ForEach(t => Console.WriteLine("{0}: ({1},{2})", t.Item1, t.Item2, t.Item3));

2
/*
     * This method takes in JSON in the form returned by javascript's
     * JSON.stringify(Object) and returns a string->string dictionary.
     * This method may be of use when the format of the json is unknown.
     * You can modify the delimiters, etc pretty easily in the source
     * (sorry I didn't abstract it--I have a very specific use).
     */ 
    public static Dictionary<string, string> jsonParse(string rawjson)
    {
        Dictionary<string, string> outdict = new Dictionary<string, string>();
        StringBuilder keybufferbuilder = new StringBuilder();
        StringBuilder valuebufferbuilder = new StringBuilder();
        StringReader bufferreader = new StringReader(rawjson);

        int s = 0;
        bool reading = false;
        bool inside_string = false;
        bool reading_value = false;
        //break at end (returns -1)
        while (s >= 0)
        {
            s = bufferreader.Read();
            //opening of json
            if (!reading)
            {
                if ((char)s == '{' && !inside_string && !reading) reading = true;
                continue;
            }
            else
            {
                //if we find a quote and we are not yet inside a string, advance and get inside
                if (!inside_string)
                {
                    //read past the quote
                    if ((char)s == '\"') inside_string = true;
                    continue;
                }
                if (inside_string)
                {
                    //if we reached the end of the string
                    if ((char)s == '\"')
                    {
                        inside_string = false;
                        s = bufferreader.Read(); //advance pointer
                        if ((char)s == ':')
                        {
                            reading_value = true;
                            continue;
                        }
                        if (reading_value && (char)s == ',')
                        {
                            //we know we just ended the line, so put itin our dictionary
                            if (!outdict.ContainsKey(keybufferbuilder.ToString())) outdict.Add(keybufferbuilder.ToString(), valuebufferbuilder.ToString());
                            //and clear the buffers
                            keybufferbuilder.Clear();
                            valuebufferbuilder.Clear();
                            reading_value = false;
                        }
                        if (reading_value && (char)s == '}')
                        {
                            //we know we just ended the line, so put itin our dictionary
                            if (!outdict.ContainsKey(keybufferbuilder.ToString())) outdict.Add(keybufferbuilder.ToString(), valuebufferbuilder.ToString());
                            //and clear the buffers
                            keybufferbuilder.Clear();
                            valuebufferbuilder.Clear();
                            reading_value = false;
                            reading = false;
                            break;
                        }
                    }
                    else
                    {
                        if (reading_value)
                        {
                            valuebufferbuilder.Append((char)s);
                            continue;
                        }
                        else
                        {
                            keybufferbuilder.Append((char)s);
                            continue;
                        }
                    }
                }
                else
                {
                    switch ((char)s)
                    {
                        case ':':
                            reading_value = true;
                            break;
                        default:
                            if (reading_value)
                            {
                                valuebufferbuilder.Append((char)s);
                            }
                            else
                            {
                                keybufferbuilder.Append((char)s);
                            }
                            break;
                    }
                }
            }
        }
        return outdict;
    }

이 답변은 배열 / 목록이없는 JSON에서 잘 작동하는 것처럼 보이지만 [또는 ]문자 (배열 또는 목록 구조 구분) 의 존재를 전혀 처리 할 수 ​​없습니다 .
Special Sauce

여기에서 JSON 역 직렬화를 다시 구현하는 것 같습니다. 여러 가지 이유로 문제에 대한 매우 나쁜 해결책이라고 생각합니다. 더 나은 접근 방식에 대해 가장 많이 찬성 된 답변을 참조하십시오.
Zero3

-1

당신이 사용하는 JSON클래스를 다음 호출 GetData()기능을.

/// <summary>
/// This class encodes and decodes JSON strings.
/// Spec. details, see http://www.json.org/
///
/// JSON uses Arrays and Objects. These correspond here to the datatypes ArrayList and Hashtable.
/// All numbers are parsed to doubles.
/// </summary>
    using System;
    using System.Collections;
    using System.Globalization;
    using System.Text;

public class JSON
{
    public const int TOKEN_NONE = 0;
    public const int TOKEN_CURLY_OPEN = 1;
    public const int TOKEN_CURLY_CLOSE = 2;
    public const int TOKEN_SQUARED_OPEN = 3;
    public const int TOKEN_SQUARED_CLOSE = 4;
    public const int TOKEN_COLON = 5;
    public const int TOKEN_COMMA = 6;
    public const int TOKEN_STRING = 7;
    public const int TOKEN_NUMBER = 8;
    public const int TOKEN_TRUE = 9;
    public const int TOKEN_FALSE = 10;
    public const int TOKEN_NULL = 11;

    private const int BUILDER_CAPACITY = 2000;

    /// <summary>
    /// Parses the string json into a value
    /// </summary>
    /// <param name="json">A JSON string.</param>
    /// <returns>An ArrayList, a Hashtable, a double, a string, null, true, or false</returns>
    public static object JsonDecode(string json)
    {
        bool success = true;

        return JsonDecode(json, ref success);
    }

    /// <summary>
    /// Parses the string json into a value; and fills 'success' with the successfullness of the parse.
    /// </summary>
    /// <param name="json">A JSON string.</param>
    /// <param name="success">Successful parse?</param>
    /// <returns>An ArrayList, a Hashtable, a double, a string, null, true, or false</returns>
    public static object JsonDecode(string json, ref bool success)
    {
        success = true;
        if (json != null) {
            char[] charArray = json.ToCharArray();
            int index = 0;
            object value = ParseValue(charArray, ref index, ref success);
            return value;
        } else {
            return null;
        }
    }

    /// <summary>
    /// Converts a Hashtable / ArrayList object into a JSON string
    /// </summary>
    /// <param name="json">A Hashtable / ArrayList</param>
    /// <returns>A JSON encoded string, or null if object 'json' is not serializable</returns>
    public static string JsonEncode(object json)
    {
        StringBuilder builder = new StringBuilder(BUILDER_CAPACITY);
        bool success = SerializeValue(json, builder);
        return (success ? builder.ToString() : null);
    }

    protected static Hashtable ParseObject(char[] json, ref int index, ref bool success)
    {
        Hashtable table = new Hashtable();
        int token;

        // {
        NextToken(json, ref index);

        bool done = false;
        while (!done) {
            token = LookAhead(json, index);
            if (token == JSON.TOKEN_NONE) {
                success = false;
                return null;
            } else if (token == JSON.TOKEN_COMMA) {
                NextToken(json, ref index);
            } else if (token == JSON.TOKEN_CURLY_CLOSE) {
                NextToken(json, ref index);
                return table;
            } else {

                // name
                string name = ParseString(json, ref index, ref success);
                if (!success) {
                    success = false;
                    return null;
                }

                // :
                token = NextToken(json, ref index);
                if (token != JSON.TOKEN_COLON) {
                    success = false;
                    return null;
                }

                // value
                object value = ParseValue(json, ref index, ref success);
                if (!success) {
                    success = false;
                    return null;
                }

                table[name] = value;
            }
        }

        return table;
    }

    protected static ArrayList ParseArray(char[] json, ref int index, ref bool success)
    {
        ArrayList array = new ArrayList();

        // [
        NextToken(json, ref index);

        bool done = false;
        while (!done) {
            int token = LookAhead(json, index);
            if (token == JSON.TOKEN_NONE) {
                success = false;
                return null;
            } else if (token == JSON.TOKEN_COMMA) {
                NextToken(json, ref index);
            } else if (token == JSON.TOKEN_SQUARED_CLOSE) {
                NextToken(json, ref index);
                break;
            } else {
                object value = ParseValue(json, ref index, ref success);
                if (!success) {
                    return null;
                }

                array.Add(value);
            }
        }

        return array;
    }

    protected static object ParseValue(char[] json, ref int index, ref bool success)
    {
        switch (LookAhead(json, index)) {
            case JSON.TOKEN_STRING:
                return ParseString(json, ref index, ref success);
            case JSON.TOKEN_NUMBER:
                return ParseNumber(json, ref index, ref success);
            case JSON.TOKEN_CURLY_OPEN:
                return ParseObject(json, ref index, ref success);
            case JSON.TOKEN_SQUARED_OPEN:
                return ParseArray(json, ref index, ref success);
            case JSON.TOKEN_TRUE:
                NextToken(json, ref index);
                return true;
            case JSON.TOKEN_FALSE:
                NextToken(json, ref index);
                return false;
            case JSON.TOKEN_NULL:
                NextToken(json, ref index);
                return null;
            case JSON.TOKEN_NONE:
                break;
        }

        success = false;
        return null;
    }

    protected static string ParseString(char[] json, ref int index, ref bool success)
    {
        StringBuilder s = new StringBuilder(BUILDER_CAPACITY);
        char c;

        EatWhitespace(json, ref index);

        // "
        c = json[index++];

        bool complete = false;
        while (!complete) {

            if (index == json.Length) {
                break;
            }

            c = json[index++];
            if (c == '"') {
                complete = true;
                break;
            } else if (c == '\\') {

                if (index == json.Length) {
                    break;
                }
                c = json[index++];
                if (c == '"') {
                    s.Append('"');
                } else if (c == '\\') {
                    s.Append('\\');
                } else if (c == '/') {
                    s.Append('/');
                } else if (c == 'b') {
                    s.Append('\b');
                } else if (c == 'f') {
                    s.Append('\f');
                } else if (c == 'n') {
                    s.Append('\n');
                } else if (c == 'r') {
                    s.Append('\r');
                } else if (c == 't') {
                    s.Append('\t');
                } else if (c == 'u') {
                    int remainingLength = json.Length - index;
                    if (remainingLength >= 4) {
                        // parse the 32 bit hex into an integer codepoint
                        uint codePoint;
                        if (!(success = UInt32.TryParse(new string(json, index, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out codePoint))) {
                            return "";
                        }
                        // convert the integer codepoint to a unicode char and add to string
                        s.Append(Char.ConvertFromUtf32((int)codePoint));
                        // skip 4 chars
                        index += 4;
                    } else {
                        break;
                    }
                }

            } else {
                s.Append(c);
            }

        }

        if (!complete) {
            success = false;
            return null;
        }

        return s.ToString();
    }

    protected static double ParseNumber(char[] json, ref int index, ref bool success)
    {
        EatWhitespace(json, ref index);

        int lastIndex = GetLastIndexOfNumber(json, index);
        int charLength = (lastIndex - index) + 1;

        double number;
        success = Double.TryParse(new string(json, index, charLength), NumberStyles.Any, CultureInfo.InvariantCulture, out number);

        index = lastIndex + 1;
        return number;
    }

    protected static int GetLastIndexOfNumber(char[] json, int index)
    {
        int lastIndex;

        for (lastIndex = index; lastIndex < json.Length; lastIndex++) {
            if ("0123456789+-.eE".IndexOf(json[lastIndex]) == -1) {
                break;
            }
        }
        return lastIndex - 1;
    }

    protected static void EatWhitespace(char[] json, ref int index)
    {
        for (; index < json.Length; index++) {
            if (" \t\n\r".IndexOf(json[index]) == -1) {
                break;
            }
        }
    }

    protected static int LookAhead(char[] json, int index)
    {
        int saveIndex = index;
        return NextToken(json, ref saveIndex);
    }

    protected static int NextToken(char[] json, ref int index)
    {
        EatWhitespace(json, ref index);

        if (index == json.Length) {
            return JSON.TOKEN_NONE;
        }

        char c = json[index];
        index++;
        switch (c) {
            case '{':
                return JSON.TOKEN_CURLY_OPEN;
            case '}':
                return JSON.TOKEN_CURLY_CLOSE;
            case '[':
                return JSON.TOKEN_SQUARED_OPEN;
            case ']':
                return JSON.TOKEN_SQUARED_CLOSE;
            case ',':
                return JSON.TOKEN_COMMA;
            case '"':
                return JSON.TOKEN_STRING;
            case '0': case '1': case '2': case '3': case '4':
            case '5': case '6': case '7': case '8': case '9':
            case '-':
                return JSON.TOKEN_NUMBER;
            case ':':
                return JSON.TOKEN_COLON;
        }
        index--;

        int remainingLength = json.Length - index;

        // false
        if (remainingLength >= 5) {
            if (json[index] == 'f' &&
                json[index + 1] == 'a' &&
                json[index + 2] == 'l' &&
                json[index + 3] == 's' &&
                json[index + 4] == 'e') {
                index += 5;
                return JSON.TOKEN_FALSE;
            }
        }

        // true
        if (remainingLength >= 4) {
            if (json[index] == 't' &&
                json[index + 1] == 'r' &&
                json[index + 2] == 'u' &&
                json[index + 3] == 'e') {
                index += 4;
                return JSON.TOKEN_TRUE;
            }
        }

        // null
        if (remainingLength >= 4) {
            if (json[index] == 'n' &&
                json[index + 1] == 'u' &&
                json[index + 2] == 'l' &&
                json[index + 3] == 'l') {
                index += 4;
                return JSON.TOKEN_NULL;
            }
        }

        return JSON.TOKEN_NONE;
    }

    protected static bool SerializeValue(object value, StringBuilder builder)
    {
        bool success = true;

        if (value is string) {
            success = SerializeString((string)value, builder);
        } else if (value is Hashtable) {
            success = SerializeObject((Hashtable)value, builder);
        } else if (value is ArrayList) {
            success = SerializeArray((ArrayList)value, builder);
        } else if ((value is Boolean) && ((Boolean)value == true)) {
            builder.Append("true");
        } else if ((value is Boolean) && ((Boolean)value == false)) {
            builder.Append("false");
        } else if (value is ValueType) {
            // thanks to ritchie for pointing out ValueType to me
            success = SerializeNumber(Convert.ToDouble(value), builder);
        } else if (value == null) {
            builder.Append("null");
        } else {
            success = false;
        }
        return success;
    }

    protected static bool SerializeObject(Hashtable anObject, StringBuilder builder)
    {
        builder.Append("{");

        IDictionaryEnumerator e = anObject.GetEnumerator();
        bool first = true;
        while (e.MoveNext()) {
            string key = e.Key.ToString();
            object value = e.Value;

            if (!first) {
                builder.Append(", ");
            }

            SerializeString(key, builder);
            builder.Append(":");
            if (!SerializeValue(value, builder)) {
                return false;
            }

            first = false;
        }

        builder.Append("}");
        return true;
    }

    protected static bool SerializeArray(ArrayList anArray, StringBuilder builder)
    {
        builder.Append("[");

        bool first = true;
        for (int i = 0; i < anArray.Count; i++) {
            object value = anArray[i];

            if (!first) {
                builder.Append(", ");
            }

            if (!SerializeValue(value, builder)) {
                return false;
            }

            first = false;
        }

        builder.Append("]");
        return true;
    }

    protected static bool SerializeString(string aString, StringBuilder builder)
    {
        builder.Append("\"");

        char[] charArray = aString.ToCharArray();
        for (int i = 0; i < charArray.Length; i++) {
            char c = charArray[i];
            if (c == '"') {
                builder.Append("\\\"");
            } else if (c == '\\') {
                builder.Append("\\\\");
            } else if (c == '\b') {
                builder.Append("\\b");
            } else if (c == '\f') {
                builder.Append("\\f");
            } else if (c == '\n') {
                builder.Append("\\n");
            } else if (c == '\r') {
                builder.Append("\\r");
            } else if (c == '\t') {
                builder.Append("\\t");
            } else {
                int codepoint = Convert.ToInt32(c);
                if ((codepoint >= 32) && (codepoint <= 126)) {
                    builder.Append(c);
                } else {
                    builder.Append("\\u" + Convert.ToString(codepoint, 16).PadLeft(4, '0'));
                }
            }
        }

        builder.Append("\"");
        return true;
    }

    protected static bool SerializeNumber(double number, StringBuilder builder)
    {
        builder.Append(Convert.ToString(number, CultureInfo.InvariantCulture));
        return true;
    }
}

//parse and show entire json in key-value pair
    Hashtable HTList = (Hashtable)JSON.JsonDecode("completejsonstring");
        public void GetData(Hashtable HT)
        {           
            IDictionaryEnumerator ienum = HT.GetEnumerator();
            while (ienum.MoveNext())
            {
                if (ienum.Value is ArrayList)
                {
                    ArrayList arnew = (ArrayList)ienum.Value;
                    foreach (object obj in arnew)                    
                    {
                        Hashtable hstemp = (Hashtable)obj;
                        GetData(hstemp);
                    }
                }
                else
                {
                    Console.WriteLine(ienum.Key + "=" + ienum.Value);
                }
            }
        }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.