Эквивалент JObject.SelectToken в.NET
Мне нужно удалить внешний узел JSON. Вот пример:
{
app: {
...
}
}
Любые идеи о том, как удалить внешний узел, поэтому мы получаем только
{
...
}
БЕЗ использования JSON.NET, только инструменты в.NET Framework (C#).
В Json.NET я использовал:
JObject.Parse(json).SelectToken("app").ToString();
В качестве альтернативы, любая конфигурация DataContractJsonSerializer
, так что он игнорирует корень при десериализации, также будет работать. Теперь я делаю десериализацию так:
protected T DeserializeJsonString<T>(string jsonString)
{
T tempObject = default(T);
using (var memoryStream = new MemoryStream(Encoding.Unicode.GetBytes(jsonString)))
{
var serializer = new DataContractJsonSerializer(typeof(T));
tempObject = (T)serializer.ReadObject(memoryStream);
}
return tempObject;
}
Обратите внимание, что имя свойства корневого объекта может отличаться от случая к случаю. Например, это может быть "transaction"
,
Спасибо за любое предложение.
1 ответ
Там нет эквивалента SelectToken
встроенный в.Net. Но если вы просто хотите развернуть внешний корневой узел и заранее не знаете имя узла, у вас есть следующие варианты.
Если вы используете.Net 4.5 или более позднюю версию, вы можете
Dictionary<string, T>
сDataContractJsonSerializer.UseSimpleDictionaryFormat = true
:protected T DeserializeNestedJsonString<T>(string jsonString) { using (var memoryStream = new MemoryStream(Encoding.Unicode.GetBytes(jsonString))) { var serializer = new DataContractJsonSerializer(typeof(Dictionary<string, T>)); serializer.UseSimpleDictionaryFormat = true; var dictionary = (Dictionary<string, T>)serializer.ReadObject(memoryStream); if (dictionary == null || dictionary.Count == 0) return default(T); else if (dictionary.Count == 1) return dictionary.Values.Single(); else { throw new InvalidOperationException("Root object has too many properties"); } } }
Обратите внимание, что если ваш корневой объект содержит более одного свойства, вы не можете десериализовать в
Dictionary<TKey, TValue>
получить первое свойство, поскольку порядок элементов в этом классе не определен.В любой версии.Net, поддерживающей сериализаторы контрактов данных, вы можете воспользоваться тем, что
DataContractJsonSerializer
наследуется отXmlObjectSerializer
звонитьJsonReaderWriterFactory.CreateJsonReader()
создатьXmlReader
который на самом деле читает JSON, а затем переходит к первому вложенному "элементу":protected T DeserializeNestedJsonStringWithReader<T>(string jsonString) { var reader = JsonReaderWriterFactory.CreateJsonReader(Encoding.Unicode.GetBytes(jsonString), System.Xml.XmlDictionaryReaderQuotas.Max); int elementCount = 0; while (reader.Read()) { if (reader.NodeType == System.Xml.XmlNodeType.Element) elementCount++; if (elementCount == 2) // At elementCount == 1 there is a synthetic "root" element { var serializer = new DataContractJsonSerializer(typeof(T)); return (T)serializer.ReadObject(reader, false); } } return default(T); }
Эта техника выглядит странно (разбор JSON с
XmlReader
?), но с некоторой дополнительной работой должно быть возможно расширить эту идею, чтобы создать SAX-подобную функциональность синтаксического анализа для JSON, которая похожа наSelectToken()
, пропуская вперед в JSON, пока не будет найдено требуемое свойство, затем десериализовать его значение.Например, для выбора и десериализации определенных именованных свойств, а не только первого корневого свойства, может использоваться следующее:
public static class DataContractJsonSerializerExtensions { public static T DeserializeNestedJsonProperty<T>(string jsonString, string rootPropertyName) { // Check for count == 2 because there is a synthetic <root> element at the top. Predicate<Stack<string>> match = s => s.Count == 2 && s.Peek() == rootPropertyName; return DeserializeNestedJsonProperties<T>(jsonString, match).FirstOrDefault(); } public static IEnumerable<T> DeserializeNestedJsonProperties<T>(string jsonString, Predicate<Stack<string>> match) { DataContractJsonSerializer serializer = null; using (var reader = JsonReaderWriterFactory.CreateJsonReader(Encoding.UTF8.GetBytes(jsonString), XmlDictionaryReaderQuotas.Max)) { var stack = new Stack<string>(); while (reader.Read()) { if (reader.NodeType == System.Xml.XmlNodeType.Element) { stack.Push(reader.Name); if (match(stack)) { serializer = serializer ?? new DataContractJsonSerializer(typeof(T)); yield return (T)serializer.ReadObject(reader, false); } if (reader.IsEmptyElement) stack.Pop(); } else if (reader.NodeType == XmlNodeType.EndElement) { stack.Pop(); } } } } }
Посмотрите Отображение Между JSON и XML для деталей о том, как
JsonReaderWriterFactory
отображает JSON в XML.