2014-09-04 2 views
5

json을 이와 같이 deserialize해야합니다 (DICOM에 정의 된대로 - 국제 표준이므로 형식을 변경할 수 없습니다!)데이터의 속성 값을 기반으로 Json.Net을 사용하여 직렬화 해제 할 객체 유형을 선택하는 방법

{ 
.... 
"00080060": { 
    "Value": [ 
    "US" 
    ], 
    "vr": "CS" 
}, 
"00080070": { 
    "Value": [ 
    "ACME Products" 
    ], 
    "vr": "LO" 
}, 
"00080090": { 
    "Value": [ 
    { 
     "AlphabeticName": "Better^Make^U.^MD" 
    } 
    ], 
    "vr": "PN" 
}, 
"00081110": { 
    "Value": [ 
    { 
     "00080008": { 
     "Value": [ 
      "XX_0", 
      "OIU", 
      null, 
      "PPP" 
     ], 
     "vr": "CS" 
     } 
    }, 
    {}, 
    { 
     "00080008": { 
     "Value": [ 
      "XX_2", 
      "OIU", 
      null, 
      "PPP" 
     ], 
     "vr": "CS" 
     } 
    } 
    ], 
    "vr": "SQ" 
}, 

긴 목록의 각 속성 (!))의 이름 (위의 예에서 0008XXXX을 갖고, 서브 속성 "VR"및 값을 가진다. 대부분의 경우 Value는 단순히 객체 (문자열 또는 숫자)의 배열이며 괜찮습니다. 그러나 특별한 경우 2 개 (위와 같은 PN 및 SQ)에는 특별한 처리가 필요하며 SQ의 경우 실제로는 최상위 오브젝트를 다시 반복적으로 중첩시킬 수 있습니다. (재귀 적으로 순환 적으로 중첩 될 수 있습니다 ...)

그래서 - "vr"값을 검사하고 사용할 유형을 직렬화 해제하는 동안 간단한 메소드가 필요합니다. 관련된 "가치"에 대해 - 그렇게 할 수있는 간단한 수단이 있습니까? 물론, vr이 Value 이전이나 이후에 올 수 있다는 사실은 원격 구현에 따라 상황을 더욱 복잡하게 만들 수 있습니다 ...

json.net의 ContractResolver 및 JsonConverter 메커니즘을 살펴 봤지만 ContractResolver는 저를 제공하지 않는 것 같습니다. 선택을 할 수 있도록 읽을 데이터에 대한 액세스 및 JsonConverter 파생 클래스는 json.net이 동글 (그렇지 않으면 너무 잘!) 인 것의 대부분을 다시 구현해야하는 것처럼 보일 것입니다 .--(

내가 여기에 몇 가지 분명하고 간단한 해결책을 놓친 거지?

+0

이'JObject'는 당신이 필요로하는 것입니다 : 여기

var dict = JsonConvert.DeserializeObject<Dictionary<string, Node>>(json, new NodeConverter()); 

데모입니다 :

그래서, 여기 당신이 당신의 JSON 직렬화 얼마나입니다, 모두 함께 넥타이. 불행히도, 나는 그것을 파싱하는 데 충분한 시간이 없다. –

답변

5

헉,이는 사용자 정의를 사용하여 그것의 의미를 할 수 있어야한다. 그러나, 작업하기 어려운 형식입니다. 컨버터 내부에 JObject을 사용하면 대부분의 무거운 물건들로부터 우리를 보호 할 수 있습니다. 하지만 먼저 데이터를 비 직렬화하기 위해 두 가지 클래스를 정의해야합니다.

첫 번째 강의는 Node입니다. 여기에는 Value 목록과 vr 목록이 포함됩니다.

class Node 
{ 
    public IList Value { get; set; } 
    public string vr { get; set; } 
} 

두 번째 클래스는 "PN"케이스의 항목을 유지하는 데 필요합니다.

class PnItem 
{ 
    public string AlphabeticName { get; set; } 
} 

다음은 변환기 코드입니다. 변환기는 vr 속성을보고 해당 정보를 사용하여 Value에 대한 올바른 유형의 목록을 만들 수 있습니다. 은 "SQ"경우에 우리가 List<Dictionary<string, Node>>의 직렬화 복원되는

class NodeConverter : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return (objectType == typeof(Node)); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     JObject jo = JObject.Load(reader); 
     Node node = new Node(); 
     node.vr = (string)jo["vr"]; 
     if (node.vr == "PN") 
     { 
      node.Value = jo["Value"].ToObject<List<PnItem>>(serializer); 
     } 
     else if (node.vr == "SQ") 
     { 
      node.Value = jo["Value"].ToObject<List<Dictionary<string, Node>>>(serializer); 
     } 
     else 
     { 
      node.Value = jo["Value"].ToObject<List<string>>(serializer); 
     } 
     return node; 
    } 

    public override bool CanWrite 
    { 
     get { return false; } 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 
} 

알 수 있습니다. 이것은 재귀 구조를 다룹니다. Json.Net이 노드를 deserialize하려고 할 때마다 변환기로 다시 호출합니다. Dictionary을 사용하여 속성 이름이 다를 수 있다는 사실을 처리합니다 (예 : "00080070", "00080090"등). 루트에서 동일한 이유로 Dictionary<string, Node>으로 deserialize해야합니다. https://dotnetfiddle.net/hsFlxU

+1

절대적으로 화려한 - 그냥 내가 필요한 것! 나는 명료성을 위해 빠뜨 렸던 다른 기이 한 것들 중 일부에 맞추기 위해 조금 수정해야했다.전체 썬싱은 json 배열입니다.) 그래서 최상위 레벨을위한 동일한 더블 레벨 제네릭을 사용하게되었습니다. – medconn

+0

아마도 몇 가지 더 세부 사항이 남아 있다고 생각했습니다. 귀하의 필요에 맞게이 솔루션을 적용 할 수있어서 다행입니다. –