Работа с плохим JSON.parse() в node безопасно. Работа с json в с
Быстрая работа с JSON в Swift / Хабр
data -> [Node] -> [Item] -> id: String, pos: [Int], coo: [Double]
Требуется распарсить и получить массив объектов типа Item соответсвенно имеющих строковое поле id, поле pos — целочисленный массив и поле coo — массив чисел с плавающей точкой.
Вариант первый — использование сторонней библиотеки:
Надо сказать что все попавшиеся мне решения использовали в качестве парсера стандартный NSJSONSerialization, а свою задачу видели исключительно в добавлении “синтаксического сахара” и более строгой типизации. В качестве примера возьмем одну из наиболее популярных SwiftyJSON:
Вариант второй — использование «чистого» swift:
let json = try! NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions()) if let nodes = (json as? [String: AnyObject])?["data"] as? [[[String: AnyObject]]] { for node in nodes { for item in node { if let id = item["id"] as? String, let pos = item["pos"] as? [Int], let coo = item["coo"] as? [Double] { Item(id: id, pos: pos, coo: coo) } } } } Наш «велосипед» справился за 6 секунд (80% от изначального), но все равно очень долго.Поведение класса NSJSONSerialization в Swift'е полностью аналогично его поведению в Objective C, а значит результатом парсинга будет некая иерархия состоящая из объектов типа NSDictionary, NSArray, NSNumber, NSString и NSNull. Данная же команда преобразует объекты этих классов в структуры Swift'а Array и Dictionary, а значит копирует данные! (Массивы в Swift более сходны с массивами в C++ чем в Objective C)
Чтобы избежать подобного копирования попробуем не использовать красивые типизированные массивы Swift'a.
Вариант третий — без использования Array и Dictionary:
let json = try! NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions()) if let nodes = (json as? NSDictionary)?["data"] as? NSArray { for node in nodes { if let node = node as? NSArray { for item in node { if let item = item as? NSDictionary, let id = item["id"] as? NSString, let pos = item["pos"] as? NSArray, let coo = item["coo"] as? NSArray { var _pos = [Int](count: pos.count, repeatedValue: 0) var _coo = [Double](count: coo.count, repeatedValue: 0) for var i = 0; i < pos.count; i++ { if let p = pos[i] as? NSNumber { _pos.append(p.integerValue) } } for var i = 0; i < coo.count; i++ { if let c = coo[i] as? NSNumber { _coo.append(c.doubleValue) } } Item(id: String(id), pos: _pos, coo: _coo) } } } } } Выглядит, конечно, ужасно. Но нас интересует прежде всего скорость работы: 2 сек (почти в 4 раза быстрее SwiftyJSON!)habr.com
Работа с JSON в 1С (до версии платформы 8.3.6)
В связи с тем, что в платформе версии 8.3.6 и старше появились встроенные объекты для работы с JSON, эта статья более не является актуальной, просьба проследовать в новую статью о работе с JSON в 1С.
Данную статью не убираю, ибо не всегда есть возможность обновить платформу до новой версии, возможно кому-то пригодится.
JSON — популярный, в настоящее время, формат, который часто используется при обмене данными с веб-сайтами или веб-сервисами. Стандартных средств для работы с JSON в 1С не существует, и в этой статье я расскажу о том, как восполнить этот недостаток своими силами.
Для начала следует сказать, что при работе с JSON требуется всего две основные функции: чтение JSON-данных и формирование JSON-данных.
Начнем, пожалуй с чтения. Дело в том, что данные в формате JSON выглядят примерно вот так:
{ "firstName": "Иван", "lastName": "Иванов", "address": { "streetAddress": "Московское ш., 101, кв.101", "city": "Ленинград", "postalCode": 101101 }, "phoneNumbers": [ "812 123-1234", "916 123-4567" ] }
{ "firstName": "Иван", "lastName": "Иванов", "address": { "streetAddress": "Московское ш., 101, кв.101", "city": "Ленинград", "postalCode": 101101 }, "phoneNumbers": [ "812 123-1234", "916 123-4567" ] } |
Видно, что все это достаточно сильно напоминает структуру, поэтому JSON-данные преобразуются именно в структуру, итак:
Функция ЗаполнитьСтруктуруИзJSON(<ДанныеJSON>)
<ДанныеJSON> — обязательный параметр, строка формата JSON, которую необходимо прочитать.
Возвращаемое значение: структура.
Вторая функция превращает значения с типами структура, массив или таблица значений в строку JSON-данных:
Функция СформироватьСтрокуJSON(<Объект>)
<Объект> — обязательный параметр, должен иметь тип «Структура», «Массив» или «ТаблицаЗначений».
Возвращаемое значение: строка JSON-данных.
Посмотреть полный текст модуля можно в виде cf-файла или текстового файла.
Загрузка...1c-programmer-blog.ru
json - Работа с схемой JSON в CouchDB
Вы задаете тот же вопрос, который у меня был в течение многих лет, изучая потенциальные преимущества CouchDB в случаях использования форм с избыточными данными.
Вначале я надеялся найти подход, который позволяет проверять достоверность данных на основе одного и того же кода схемы JSON и кода проверки - сервера и клиента. Оказалось, что это не только возможно, но и некоторые дополнительные преимущества.
Где помещается схема в CouchDB? Как обычный документ? Проектный документ? Или, может быть, сохранить их как файл? Но если я буду проверять их, особенно на стороне сервера в функции validate_doc_update, они должны храниться в проектных документах.
Вы правы. Проект doc (ddoc), который также включает функцию validate_doc_update для выполнения проверки перед обновлением doc, является наиболее распространенным местом для размещения этих схем. this в функции validate_doc_update является самой ddoc - все, что включено в ddoc, может быть доступ из кода проверки.
Я начал хранить схемы как объект JSON в моем общем библиотечном свойстве/папке для модулей commonjs, например. lib/schemata.json. Свойство type моих документов указало ключ схемы, который должна получить подтверждение проверки документа. type: 'adr' → lib/schemata/adr. Схема может также ссылаться на другие схемы на каждое свойство - рекурсивная функция проверки прошла до конца любого свойства независимо от того, какой тип вложенных свойств был. Он хорошо зарекомендовал себя в первом проекте.
{ "person": { "name": "/type/name", "adr": "/type/adr", ... }, "name": { "forname": { "minlenght": 2, "maxlength": 42, ... }, "surname": { ... } }, "adr": { ... } }В этот момент мои схемы были сохранены в одном файле в репозитории (я использую erica в качестве инструмента для загрузки для ddocs). Затем я понял, что когда я храню каждую схему в отдельном файле, например. adr.json, geo.json, tel.json и т.д. это приводит к тому же JSON-структуре на серверах ddoc, как и раньше, с однопользовательским подходом. Но он был более подходящим для управления исходным кодом. Мало того, что файлы меньшего размера приводят к меньшим конфликтам слияния и более чистой истории фиксации, также было включено управление зависимостями схем через субрепозитории (подмодули).
Другая мысль заключалась в том, чтобы использовать CouchDB как место хранения и управления схемами. Но, как вы уже упоминали об этом, схемы должны быть доступны в функции validate_doc_update. Сначала я попробовал подход с обработчиком обновлений - каждое обновление doc должно передать обработчик обновления проверки, который сам по себе получает правильную схему из CouchDB:
Но этот подход не работает хорошо с вложенными схемами. Хуже того - для предотвращения обновлений doc без проверки через обработчик мне пришлось использовать прокси перед CouchDB, чтобы скрыть прямые встроенные пути обновления док-станции (например, POST to/the/doc/_id). Я не нашел способ обнаружить в функции validate_doc_update, был ли обработчик обновления задействован до или нет (возможно, у кого-то есть? Я был бы рад прочитать такое решение.).
Во время этого исследования проблема с различными версиями той же схемы появляется на моем радаре. Как мне это сделать? Должны ли все документы из того же типа быть действительными в отношении одной и той же версии схемы (что означает необходимость переноса данных в формате db перед почти каждой версией схемы)? Если свойство type также содержит номер версии? и др.
Но подождите! Что делать, если схема документа прикреплена к самому документу? Это:
- предоставит совместимую версию для содержимого документа для каждого документа
- быть доступным в функции validate_doc_update (в oldDoc)
- может быть реплицирован без прав доступа администратора (как вам нужно для обновлений ddoc)
- будет включен в каждый ответ для запроса на стороне клиента
Это звучало очень интересно, и мне кажется, что это самый подход CouchDB-ish до сих пор. Сказать это ясно - схема документа прикреплена к самому документу - означает его сохранение в собственности документа. Как хранилище как вложение, так и использование самой схемы в качестве структуры документа не были успешными.
Наиболее чувствительным моментом такого подхода является C(создать) в жизненном круге CRUD документа. Существует множество различных решений, которые можно представить, чтобы убедиться, что присоединенная схема "правильная и приемлемая". Но это зависит от вашего определения этих терминов в вашем конкретном проекте.
Есть ли какая-нибудь библиотека (лучше будет JavaScript) с работами в CouchDB и Client (веб-браузер)? Библиотека с я мог бы генерировать JSON и автоматически проверять их?
Я начал реализовывать с помощью популярного плагина проверки JQuery. Я мог бы использовать схему как конфигурацию и автоматически проверять на стороне клиента. На стороне сервера я извлек функции проверки как модуль commonjs. Я ожидал, что позже найду модульный способ управления кодом, который предотвратит дублирование кода.
Оказалось, что большинство существующих фреймворков валидации очень хороши в сопоставлении шаблонов и валидации с одним свойством, но не способны проверять значения зависимостей в одном документе. Также требования к определению схемы часто слишком проприетарны. Для меня правильное правило для выбора правильного определения схемы: предпочитайте стандартизованное определение (jsonschema.org, microdata, rdfa, hcard и т.д.) Над собственной реализацией. Если вы оставите структуру и имена свойств как они есть, вам потребуется меньше документации, меньше трансформации, а иногда вы получите совместимость с зарубежным программным обеспечением, которое ваши пользователи используют также (например, календари, адресные книги и т.д.) Автоматически. Если вы хотите реализовать HTML-презентацию для своих документов, вы хорошо подготовлены к ее выполнению в семантическом веб-и-SEO-режиме.
И, наконец, - не желая звучать высокомерно - написать схему проверки достоверности не сложно. Возможно, вы хотите прочитать исходный код плагина проверки JQuery - я уверен, что вы находите это, как я, удивительным. Во времена, когда скорость оттока интерфейсных фреймворков увеличивается, возможно, это самый надежный способ обеспечения собственной проверки. Кроме того, я считаю, что вы должны иметь 100% понимание реализации валидации - это критическая часть вашего приложения. И если вы понимаете иностранную реализацию - вы также можете написать библиотеку самостоятельно.
Ok. Это легкий ответ. Сожалею. Если кто-то читает это до конца и хочет увидеть его подробным в действии с примером исходного кода - upvote, и я напишу сообщение в блоге и добавлю URI в качестве комментария.
qaru.site
Работа с JSON в Scala при помощи библиотеки json4s
Все мы любим JSON. Это простой формат, хорошо читаемый, удобный при отладке, стандарт де-факто во всяких там REST-ах, и не только. Более того, JSON может быть еще и довольно компактным, например, если передавать список с именами полей один раз, а за ним — списки значений. Или если просто сжать его при помощи gzip. В мире Scala есть немало библиотек для работы с JSON, но наиболее мощной и производительной, видимо, является json4s.
Для подключения json4s к проекту прописываем в build.sbt:
"org.json4s" %% "json4s-jackson" % "3.2.11"
Простой пример декодирования JSON:
import org.json4s._import org.json4s.jackson.JsonMethods._object Json4sTests extends App { val t = parse("""{"postId": 123123123123123, "text":"ololo"}""") println(t)}
Результат:
JObject(List((postId,JInt(123123123123123)), (text,JString(ololo))))
То есть, получили AST.
С его же помощью можно собрать и сериализовать JSON объект:
val obj = JObject(List( "postId" -> JInt(123123123123123L), "text" -> JString("ololo")))val doc = render(obj)val compactJson = compact(doc)val prettyJson = pretty(doc)println(s"compact:\n$compactJson\n\npretty:\n$prettyJson")
Результат:
compact: {"postId":123123123123123,"text":"ololo"}pretty:{ "postId":123123123123123, "text":"ololo"}
Строительство AST при помощи JObject’ов и JString’ов довольно многословно, давайте это исправим:
import org.json4s._import org.json4s.jackson.JsonMethods._import org.json4s.JsonDSL._object Json4sTests extends App { val obj = ("type" -> "post") ~ ("info" -> ("postId" -> 12345L) ~ ("tags" -> Seq("ololo", "trololo")) ) println(compact(render(obj)))}
Результат:
{"type":"post","info":{"postId":12345,"tags":["ololo","trololo"]}}
Что еще многословно — это парсить AST используя только паттерн матчинг. Поэтому json4s предлагает XPath-подобные комбинаторы, вроде тех, что мы использовали в свое время при парсинге XML:
val json = parse( """|{"posts":[{"id":1,"text":"ololo"}, |{"id":2,"text":"trololo"}]}""".stripMargin)val postTexts: List[String] = { json \ "posts" \\ "text" \ classOf[JString]} println(s"postTexts = $postTexts")val JInt(firstPostId) = (json \ "posts")(0) \ "id" println(s"firstPostId = $firstPostId")
Результат:
postIdsObj = List(ololo, trololo)firstPostId = 1
А что, если у нас есть набор каких-то case class’ов и мы хотели бы сериализовать их в JSON? Писать сериализацию и десериализацию вручную? Конечно же нет:
import org.json4s._import org.json4s.jackson.JsonMethods._import org.json4s.jackson.Serializationobject Json4sTests extends App { sealed trait Status case object StatusOk extends Status case object StatusBanned extends Status case class User(name: (String, String, String), friends: Seq[User], status: Option[Status])
// implicit val formats = Serialization.formats(NoTypeHints) implicit val formats = { Serialization.formats(FullTypeHints(List(classOf[Status]))) }
val john = { val jane = User(("Jane", "J", "Doe"), Nil, Some(StatusBanned)) User(("John", "J", "Doe"), Seq(jane), None) }
val json = pretty(render(Extraction.decompose(john))) println(s"json:\n$json")
val decodedUser = parse(json).extract[User] println(s"decoded user: $decodedUser")}
Вывод программы:
json:{ "name" : { "_1" : "John", "_2" : "J", "_3" : "Doe" }, "friends" : [ { "name" : { "_1" : "Jane", "_2" : "J", "_3" : "Doe" }, "friends" : [ ], "status" : { "jsonClass" : "Json4sTests$StatusBanned$" } } ]}decoded user: User((John,J,Doe),List(User((Jane,J,Doe),List(), Some(StatusBanned))),None)
Как видите, все на месте, никакие данные не потерялись. Что интересно, кортежи из двух элементов кодируются как {"Jane":"Doe"} :) Если же воспользоваться альтернативным значением неявного аргумента formats, который с NoTypeHints, то программа тоже будет работать, причем в полученном JSON’е не будет страшной строчки "Json4sTests$StatusBanned$". Но значение поля status будет потеряно — при десериализации мы будем всегда получать None. Собственно, это логично, должен же status как-то кодироваться.
Что еще интересно, мы можем добавлять в сериализуемые классы Option-поля и поля со значениями по умолчанию, а также удалять поля, и это не сломает обратную совместимость. То есть, программа, в которой были сделаны такие изменения, сможет десериализовать объект, сериализованный программой до внесения изменений. Проверьте сами!
Наконец, рассмотрим последний пример. Допустим, мы хотим сериализовать данные вроде таких:
object Operation extends Enumeration { val READ, WRITE = Value}type OperationType = Operation.Value
case class Stat(min: Double, max: Double, sum: Double, count: Long)
val stats: Map[OperationType, Stat] = { Map( Operation.READ -> Stat(1.0, 2.0, 15.0, 7L), Operation.WRITE -> Stat(0.5, 3.0, 13.0, 8L) )}
В этом случае мы получим ошибку:
Exception in thread "main" org.json4s.package$MappingException: Do notknow how to serialize key of type class scala.Enumeration$Val. Considerimplementing a CustomKeySerializer.
… потому что ключами в JSON-объектах могут быть только строки. Нам нужно как-то отображать OperationType на строки и обратно. Сказано — сделано:
val OperationSerializer = new CustomKeySerializer[OperationType]( format => ( { case s: String => Operation.withName(s) }, { case k: OperationType => k.toString } ))implicit val serializationFormats = { Serialization.formats(NoTypeHints) + OperationSerializer}
val json = pretty(render(Extraction.decompose(stats)))println(s"json:\n$json")
val decodedStat = parse(json).extract[Map[OperationType, Stat]]println(s"decodedStat:\n$decodedStat")
Вывод программы:
json:{ "READ" : { "min" : 1.0, "max" : 2.0, "sum" : 15.0, "count" : 7 }, "WRITE" : { "min" : 0.5, "max" : 3.0, "sum" : 13.0, "count" : 8 }}decodedStat:Map(READ -> Stat(1.0,2.0,15.0,7), WRITE -> Stat(0.5,3.0,13.0,8))
Все в полном соответствии с нашими ожиданиями!
Больше примеров использования json4s вы можете найти на официальном сайте библиотеки, а также в репозитории на GitHub. Особое внимание уделите каталогу tests. Например, в нем можно найти интересный файлик XmlExamples.scala. Да, json4s также поддерживает и XML!
А как вы относитесь к JSON и при помощи какой библиотеки работаете с ним?
Метки: Scala, Функциональное программирование.
eax.me
json - Работа с плохим JSON.parse() в node безопасно
Лучший способ уловить неверные ошибки разбора JSON - это перевести вызовы на JSON.parse() в блок try/catch.
У вас действительно нет другого варианта - встроенная реализация генерирует исключение из недопустимых данных JSON, и единственный способ предотвратить это исключение от остановки приложения - это поймать его. Даже использование сторонней библиотеки не позволит избежать этого - они должны сделать try/catch при вызове JSON.parse() где-нибудь.
Единственная альтернатива - реализовать собственный алгоритм синтаксического анализа JSON, который может быть более прощающим в отношении недействительных структур данных, но это похоже на то, чтобы выкапывать отверстие в 1 кубический метр с небольшим ядерным оружием.
Примечание о производительности
JavaScript-движок v8, используемый Node.js не может оптимизировать функции, содержащие блок try/catch.
Обновление: v8 4.5 и выше может оптимизировать try/catch. Для более старых версий см. Ниже.
Простым обходным решением является включение логики безопасного анализа в отдельную функцию, чтобы можно было оптимизировать основную функцию:
function safelyParseJSON (json) { // This function cannot be optimised, it best to // keep it small! var parsed try { parsed = JSON.parse(json) } catch (e) { // Oh well, but whatever... } return parsed // Could be undefined! } function doAlotOfStuff () { // ... stuff stuff stuff var json = safelyParseJSON(data) // Tadaa, I just got rid of an optimisation killer! }Если разбор JSON выполняется спорадически, это может не иметь заметного влияния на производительность, но если его использовать ненадлежащим образом в функции интенсивного использования, это может привести к резкому увеличению времени отклика.
Примечание о блокировке try/catch
Следует отметить, что every.single.statement кода JavaScript в Node.js выполняется только один раз, независимо от того, вызвал ли он основную функцию или от обратного вызова или от другого модуля или чего-то еще. Таким образом, каждый оператор блокирует процесс. Это не обязательно плохо - хорошо спроектированное приложение будет тратить большую часть своего времени на ожидание внешнего ресурса (ответ базы данных, HTTP-связь, операции с файловой системой и т.д.). Поэтому очень важно, что часто исполняемый код JavaScript может быть оптимизирован движком v8, поэтому в этом заблокированном состоянии требуется как можно меньше времени - см. Примечание о производительности.
qaru.site