ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • C#의 점 표기법 문자열에서 GraphQL 구조 만들기
    카테고리 없음 2020. 8. 13. 20:49

    질문

    다음 자바스크립트 질문은 내가 해결하려고하지만 C#에서 동일한 문제입니다.

    점 2 개를 병합하는 방법 표기법 문자열을 GraphQL 쿼리 문자열로 변환

    예상 구조는

    {
        "Case": {
            "Owner": {
                "Name": null,
                "ProfilePic": null
            },
            "CaseNo": null,
            "FieldOfLaw":{
                "Name": null
            },
            "CaseType": {
                "Name": null
            },
            "CaseSubType": {
                "Name": null
            },
        },
        "Client":{
            "Policy":{
                "PolicyNo": null
            }
        }
    }

    내 현재 출력은

    {
        "Case": {
            "Owner": {
                "Name": null,
                "ProfilePic": null
            },
            "CaseNo": null,
            "FieldOfLaw": null,
            "CaseType": null,
            "CaseSubType": null
        }
    }

    아래는 ExpandoObjects를 사용하여 필요한 객체를 동적으로 생성하려는 시도입니다. 올바른 방향으로 조언이나 조언을 주시면 감사하겠습니다.

    public static void Main(string[] args)
    {
        var FieldList = new List<string>
        {
        "Case.Owner.Name",
        "Case.Owner.ProfilePic",
        "Case.CaseNo",
        "Case.FieldOfLaw.Name",
        "Case.CaseType.Name",
        "Case.CaseSubType.Name",
        "Client.Policy.PolicyNo",
        };
    
        Parser graphQL = new Parser();
        var result = graphQL.Parse(FieldList);
        Console.Write(result);
    }

    아래는 실제 파싱 방법이므로 각 요소에 대해 집계 함수를 실행하여 expando 객체를 만들고 초기 홀더에 반환합니다. 각 분할 문자열을 재귀 적으로 탐색하고 분할 목록에 더 이상 항목이 남아 있지 않으면 재귀를 종료합니다.

    public class Parser
        {
            public string Parse(List<string> fieldList)
            {
                // List<ExpandoObject> queryHolder = new List<ExpandoObject>();
                ExpandoObject intialSeed = new ExpandoObject();
    
                fieldList.Aggregate(intialSeed, (holder, field) =>
                {
                    holder = ParseToObject(holder, field.Split('.').ToList());
                    return holder;
                });
    
                return JsonConvert.SerializeObject(intialSeed);
            }
    
            public ExpandoObject ParseToObject(ExpandoObject holder, List<string> fieldSplit, string previousKey = null)
            {
                if (fieldSplit.Any())
                {
                    var item = fieldSplit.Shift();
    
                    if (item == null)
                        return holder;
    
                    // If the current item doesn't exists in the dictionary
                    if (!((IDictionary<string, object>)holder).ContainsKey(item))
                    {
                        if (((IDictionary<string, object>)holder).Keys.Count() == 0)
                            holder.TryAdd(item, null);
                        else
                            _ = ((IDictionary<string, object>)holder).GetItemByKeyRecursively(previousKey, item);
                    }
    
                    previousKey = item;
    
                    ParseToObject(holder, fieldSplit, previousKey);
                }
    
                return holder;
            }
    
        }
    

    다음은 내 두 가지 확장 메서드입니다. 예를 들어 재귀에서 3 단계로 이동할 때 GetItemByKeyRecursively 에 문제가 있습니다.

    FieldOfLaw를 추가하여 Case expandoObject에 속성을 추가하지만 Owner, CaseNo 등을 포함하는 리프로 돌아가는 방법을 모릅니다.

     public static class CollectionExtensions
        {
            public static T Shift<T>(this IList<T> list)
            {
                var shiftedElement = list.FirstOrDefault();
                list.RemoveAt(0);
                return shiftedElement;
            }
    
            public static IDictionary<string, object> GetItemByKeyRecursively(this IDictionary<string, object> dictionary, string parentKey, string keyToCreate)
            {
                foreach (string key in dictionary.Keys)
                {
                    var leaf = dictionary[key];
    
                    if (key == parentKey)
                    {
                        var @value = dictionary[key];
                        if (@value is ExpandoObject)
                        {
                            (@value as ExpandoObject).TryAdd(keyToCreate, null);
                        }
                        else if (@value == null)
                        {
                            var item = new ExpandoObject();
                            item.TryAdd(keyToCreate, null);
                            dictionary[key] = item;
                        }
                        return dictionary;
                    }
    
                    if (leaf == null)
                        continue;
    
                    return GetItemByKeyRecursively((IDictionary<string, object>)leaf, parentKey, keyToCreate);
                }
    
                return null;
            }
        }

    답변1

    대부분 선언적으로 수행 할 수없는 것은 없습니다.

    public string Parse(List<string> fieldList)
    {
        var fieldPaths = fieldList.Select(x => x.Split('.').ToList());
        var groups = fieldPaths.GroupBy(x => x.First(), x => x.Skip(1));
        return ParseGroups(groups, 1);
    }
    
    private string ParseGroups(IEnumerable<IGrouping<string, IEnumerable<string>>> groups, int level)
    {
        string indent = new string('\t', level - 1);
    
        var groupResults = groups.Select(g =>
            !g.First().Any() ? 
                $"\t{indent}{g.Key}: null" :
                $"\t{indent}{g.Key}: " + string.Join(", \n",
                     ParseGroups(g.GroupBy(x => x.First(), x => x.Skip(1)), level + 1))
        );
    
        return indent + "{\n" + string.Join(", \n", groupResults) + "\n" + indent + "}";
    }

    여기에서 전체 샘플 코드를 확인하세요. https://dotnetfiddle.net/RLygjt



     

     

     

     

    출처 : https://stackoverflow.com/questions/58917963/creating-graphql-structure-from-dot-notation-string-in-c-sharp

    댓글

Designed by Tistory.