2016-09-23 4 views
0

Это является продолжением до моего предыдущего поста, здесь: Querying and Filtering Array of JObjects with LinqJSON.NET: выпрямления JArray к JObjects внутри Linq Query

Я отправил dotnetfiddle здесь: https://dotnetfiddle.net/s75wGu

Извинения, но я не мог понять, почему я получаю сообщение об ошибке в System.Collections.Generic.IEnumerable в dotnetfiddle, но программа работает под Linqpad и Visual Studio.

Источник JSON выглядит следующим образом:

{ 
    "Object": { 
    "NM": "Name1", 
    "AA": "Val01", 
    "BB": "Val02", 
    "CC": "Val03", 
    "DD": "Val04", 
    "EE": "Val05", 
    "FF": "Val06", 
    "GG": "Val07", 
    "HH": "Val08", 
    "Object": [ 
     { 
     "NM": "Name2", 
     "AA": "Val01", 
     "BB": "Val02", 
     "CC": "Val03", 
     "DD": "Val04", 
     "EE": "Val05", 
     "FF": "Val06", 
     "GG": "Val07", 
     "HH": "Val08", 
     "Object": [ 
      { 
      "NM": "Name3", 
      "AA": "Val01", 
      "BB": "Val02", 
      "CC": "Val03", 
      "DD": "Val04", 
      "EE": "Val05", 
      "FF": "Val06", 
      "GG": "Val07", 
      "HH": "Val08" 
      }, 
      { 
      "NM": "Name4", 
      "AA": "Val01", 
      "BB": "Val02", 
      "CC": "Val03", 
      "DD": "Val04", 
      "EE": "Val05", 
      "FF": "Val06", 
      "GG": "Val07", 
      "HH": "Val08" 
      }, 
      { 
      "NM": "Name5", 
      "AA": "Val01", 
      "BB": "Val02", 
      "CC": "Val03", 
      "DD": "Val04", 
      "EE": "Val05", 
      "FF": "Val06", 
      "GG": "Val07", 
      "HH": "Val08" 
      } 
     ] 
     } 
    ] 
    } 
} 

Как вы можете видеть, код предназначен для запроса JSON документа и придавить его к List<JObject> объекта.

Предложение if (jo is JObject) должно быть просто: Если итерации Linq находит объект JObject, он создает экземпляр joWork JObject, добавляет свойства к нему, и возвращает единственный joWork объект. Это прекрасно работает.

Но моя проблема работает с предложением if (jo is JArray): Здесь я думаю, что Linq ожидает, что я вернусь к одному объекту JObject, но у меня есть массив JObjects, который я хочу вернуть как отдельные JObjects.

Выход производства моего dotnetfiddle кода заключается в следующем:

joWork-Object: { 
    "_Parent": "", 
    "NM": "Name1", 
    "AA": "Val01", 
    "BB": "Val02", 
    "CC": "Val03", 
    "DD": "Val04", 
    "EE": "Val05", 
    "FF": "Val06", 
    "GG": "Val07", 
    "HH": "Val08" 
} 
joWork-Array: { 
    "_Parent": "Name1", 
    "_Group": 1, 
    "NM": "Name2", 
    "AA": "Val01", 
    "BB": "Val02", 
    "CC": "Val03", 
    "DD": "Val04", 
    "EE": "Val05", 
    "FF": "Val06", 
    "GG": "Val07", 
    "HH": "Val08" 
} 
joWork: 
joWork-Array: { 
    "_Parent": "Name2", 
    "_Group": 2, 
    "NM": "Name5", 
    "AA": "Val01", 
    "BB": "Val02", 
    "CC": "Val03", 
    "DD": "Val04", 
    "EE": "Val05", 
    "FF": "Val06", 
    "GG": "Val07", 
    "HH": "Val08" 
} 
joWork: 
joWork: 
joWork: 

Обратите внимание, что мы имеем Имя объекта (NM) name1, Имя2, то только Name5. Я хотел бы иметь Name1, Name2, Name3, Name4 и Name5, каждый из которых имеет свойство _Parent, которое содержит свойство NM родительского объекта.

Я понимаю, что получаю только имя5, потому что оператор JArray if в моем запросе Linq возвращает только последний элемент в массиве. Я хотел бы вернуть все элементы массива. Конечный результат должен выглядеть следующим образом:

joWork-Object: { 
    "_Parent": "", 
    "NM": "Name1", 
    "AA": "Val01", 
    "BB": "Val02", 
    "CC": "Val03", 
    "DD": "Val04", 
    "EE": "Val05", 
    "FF": "Val06", 
    "GG": "Val07", 
    "HH": "Val08" 
} 
joWork-Array: { 
    "_Parent": "Name1", 
    "_Group": 1, 
    "NM": "Name2", 
    "AA": "Val01", 
    "BB": "Val02", 
    "CC": "Val03", 
    "DD": "Val04", 
    "EE": "Val05", 
    "FF": "Val06", 
    "GG": "Val07", 
    "HH": "Val08" 
} 
joWork-Array: { 
    "_Parent": "Name2", 
    "_Group": 2, 
    "NM": "Name3", 
    "AA": "Val01", 
    "BB": "Val02", 
    "CC": "Val03", 
    "DD": "Val04", 
    "EE": "Val05", 
    "FF": "Val06", 
    "GG": "Val07", 
    "HH": "Val08" 
} 
joWork-Array: { 
    "_Parent": "Name2", 
    "_Group": 2, 
    "NM": "Name4", 
    "AA": "Val01", 
    "BB": "Val02", 
    "CC": "Val03", 
    "DD": "Val04", 
    "EE": "Val05", 
    "FF": "Val06", 
    "GG": "Val07", 
    "HH": "Val08" 
} 
joWork-Array: { 
    "_Parent": "Name2", 
    "_Group": 2, 
    "NM": "Name5", 
    "AA": "Val01", 
    "BB": "Val02", 
    "CC": "Val03", 
    "DD": "Val04", 
    "EE": "Val05", 
    "FF": "Val06", 
    "GG": "Val07", 
    "HH": "Val08" 
} 
+1

Ваш вопрос немного неясен. Можете ли вы [изменить] свой вопрос, чтобы создать полную [mcve] вашей проблемы? На данный момент ваш код не компилируется. Кроме того, вам было бы полезно показать весь желаемый результат, а не только фрагменты. И вы уверены, что второй фрагмент JSON не должен быть '{" Name ":" Array1B ", ..'? – dbc

+1

Чтобы подтвердить, вы хотите вернуть * два идентичных значения 'JObject' * при посещении массива' 'Array1A ''? – dbc

+0

Извинения, вы правы. Я создам рабочий пример и объясню, что мне нужно. Я должен был опубликовать это в ближайшее время. Благодарю. – Jazimov

ответ

1

Вы можете использовать Enumerable.SelectMany() вместо Enumerable.Select() вернуть несколько объектов в запросе Linq, уплощение возвращаемый внутренний перечислимы на составляющие ее объекты для общего подсчета:

 var root = (JContainer)JToken.Parse(jsonFromFile); 

     var controlRoot = (JContainer)root["Object"]; 

     string parentKey = ""; 
     int groupId = 0; 

     var query = 
      controlRoot 
      .DescendantsAndSelf() 
      .Where(jt => (jt.Type == JTokenType.Object) || (jt.Type == JTokenType.Array)) 
      .SelectMany(jo => 
      { 
       if (jo.Parent is JProperty) 
       { 
        var ParentName = ((JProperty)jo.Parent).Ancestors() 
            .Where(jt => jt.Type == JTokenType.Property) 
            .Select(jt => ((JProperty)jt).Name.ToString()) 
            .FirstOrDefault(); 

        if (ParentName == "Object") 
        { 
         parentKey = ((JProperty)jo.Parent).AncestorsAndSelf() // Climb up the json container parent/child hierachy 
          .Select(p => p.SelectToken("NM"))     // Get the "parentKey" property in the current parent (if present) 
          .FirstOrDefault(k => k != null).ToString();   // Return the first one found. 
        } 

        if (jo is JObject) 
        { 
         // add a property for the parent 
         var joWork = new JObject(new JProperty("_Parent", parentKey)); 

         // add only the string properties in the current object 
         joWork.Add(((JObject)jo).Properties() 
          .Where(p => p.Value.Type == JTokenType.String)); 

         return new[] { joWork }; 
        } 
        else if (jo is JArray) 
        { 
         groupId++; 
         return from o in jo 
           let arrayItems = ((JObject)o).Properties().Where(p => p.Value.Type == JTokenType.String).ToList() 
           where arrayItems.Count > 0 
           select new JObject(new[] 
            { 
             new JProperty("_Parent", parentKey), 
             new JProperty("_Group", groupId), 
            } 
            .Concat(arrayItems)); 
        } 
       } 
       return Enumerable.Empty<JObject>(); 
      } 
      ) 
      .ToList(); 

     Console.WriteLine(JsonConvert.SerializeObject(query, Formatting.Indented)); 

Здесь я использую синтаксис запроса LINQ внутри метода SelectMany(), поскольку он более компактен. Альтернативным синтаксисом метода будет:

    else if (jo is JArray) 
        { 
         groupId++; 
         return jo.Select(o => 
          { 
           var arrayItems = ((JObject)o).Properties() 
            .Where(p => p.Value.Type == JTokenType.String).ToList(); 
           if (arrayItems.Count > 0) 
           { 
            var joWork = new JObject(); 

            // add a property for the parent 
            joWork.Add(new JProperty("_Parent", parentKey)); 
            joWork.Add(new JProperty("_Group", groupId)); 

            // add only the string properties in the current object 
            joWork.Add(arrayItems); 
            return joWork; 
           } 
           else 
           { 
            return null; 
           } 
          }) 
          .Where(o => o != null); 
        }