Введение в объектную нотацию JavaScript (JSON) в JavaScript и .NET

Атиф Азиз, Скотт Митчелл, Microsoft.com

Февраль 2007 г.

Область применения:
JSON
Ajax

Аннотация: В данной статье описана объектная нотация JavaScript (или JSON), открытый текстовый формат обмена данными, предоставляющая стандартизированный формат обмена данными, более подходящий для веб-приложений типа Ajax. (22 печатных страницы)

Содержание

Введение
Знакомство с литеральной нотацией в JavaScript
Сравнение JSON и XML
Создание и анализ сообщений JSON при помощи JavaScript
Работа с JSON в .NET Framework
Выводы
Ссылки

Загрузить исходный код для этой статьи.

<!----> Введение

При разработке приложения, которое будет связываться с удаленным компьютером, необходимо выбирать формат данных и протокол обмена. Существует множество открытых, стандартизированных вариантов, а оптимальный выбор зависит от требований приложений и уже существующей функциональности. Например, веб-службы на основе SOAP переводят данные в формат XML, обернутый в конверт SOAP.

Хотя XML прекрасно работает во многих прикладных ситуациях, у него есть некоторые недостатки, которые делают его менее подходящим для других ситуаций. Одной из областей применения, для которых XML не является идеальным, является веб-приложение типа Ajax. Ajax – это методика построения интерактивных веб-приложений, обеспечивающих более точную и аккуратную работу при помощи использования упрощенных и находящихся за пределами диапазона вызовов веб-сервера вместо обратной передачи полностраничных данных. Эти асинхронные вызовы посылаются с клиента, использующего JavaScript, и включают в себя форматирование данных, отправку их на веб-сервер, анализ возвращенных данных и работу с ними. Хотя многие обозреватели могут создавать, отправлять и анализировать XML, JavaScript (или JSON) предоставляет стандартизированный формат обмена данными, более подходящий для веб-приложений типа Ajax.

JSON – это открытый текстовый формат обмена данными (см. RFC 4627). Как и XML, он читаемый, не зависит от платформы и имеет широкие возможности применения. Данные, форматированные в соответствии со стандартом JSON, являются упрощенными и могут легко анализироваться с применением JavaScript, что делает этот стандарт идеальным форматом обмена данными для веб-приложений Ajax. Поскольку это в первую очередь формат данных, JSON не ограничен только веб-приложениями Ajax и может использоваться практически в любой ситуации, где приложениям необходимо обмениваться структурированной информацией в виде текста или хранить ее в таком виде.

Эта статья анализирует стандарт JSON, его отношения с JavaScript и сравнивает его с XML. Кроме того, здесь обсуждается Jayrock, реализация JSON для .NET с открытым исходным кодом, и приводятся примеры создания и анализа сообщений JSON в JavaScript и C#.

<!----> Знакомство с литеральной нотацией в JavaScript

Литералы используются в языках программирования для буквального отображения фиксированных значений, таких как постоянное целое число 4 или строка «Привет, Мир». Литералы могут использоваться в большинстве языков везде, где допускается выражение, например как часть условия управляющего оператора, входной параметр при вызове функции, в операторе присваивания для переменной и т.д. Например, следующий код на C# и Visual Basic инициализирует переменную x постоянным целым числом 42.

int x = 42;  // C#
Dim x As Integer = 42  ' Visual Basic

Различные языки программирования допускают использование литералов различных типов. Большинство языков программирования поддерживают, как минимум, литералы для скалярных типов, таких как целые числа, числа с плавающей запятой, строки и логические значения. Интересно также то, что JavaScript в дополнение к скалярным типам также поддерживает литералы для структурированных типов, таких как массивы и объекты. Это свойство также позволяет сжатый синтаксис для создания и инициализации массивов и объектов при необходимости.

Литералы массивов в JavaScript состоят из нуля или более выражений, при этом каждое выражение представляет собой элемент массива. Элементы массива заключаются в квадратные скобки ([]) и ограничиваются запятыми. В следующем примере массив определяется буквально при помощи семи строковых элементов, содержащими названия семи континентов:

var continents = ["Europe", "Asia", "Australia", "Antarctica", "North
 America", "South America", "Africa"];
alert(continents[0] + " is one of the " + continents.length + "
 continents.");

Сравните это с тем, как вы бы создавали и инициализировали массив в JavaScript без литеральной нотации:

var continents = new Array();
continents[0] = "Europe";
continents[1] = "Asia";
continents[2] = "Australia";
continents[3] = "Antarctica";
continents[4] = "North America";
continents[5] = "South America";
continents[6] = "Africa";

Объектный литерал определяет члены объекта и их значения. Список членов объекта и значения заключается в фигурные скобки ({}), а каждый член отделяется запятой. Внутри каждого члена название и значение отделяются двоеточием (:). В следующем примере объект создается и инициализируется тремя членами, названными Адрес, Город и Почтовый индекс с соответствующими значением "123 Anywhere St.", "Springfield", и "99999."

var mailingAddress = { 
     "Address"    :   "123 Anywhere St.", 
     "City"       :   "Springfield", 
     "PostalCode" :   99999
};
alert("The package will be shipped to postal code " +
 mailingAddress.PostalCode);

В представленных примерах иллюстрируется использование строковых и числовых литералов в массивах и объектных литералов. Можно также выразить целый граф, используя нотацию рекурсивно так, что элементы массива и значения члена объекта могут сами, в свою очередь, использовать литералы объектов и массивов. Например, в следующем фрагменте приведен пример объекта, имеющего массив в качестве члена (PhoneNumbers), а сам массив составлен из списка объектов.

var contact = {
     "Name": "John Doe",
     "PermissionToCall": true,
     "PhoneNumbers": [ 
       {
           "Location": "Home",
           "Number": "555-555-1234"
       },
       {
           "Location": "Work",
           "Number": "555-555-9999 Ext. 123"
       }
     ]
};
if (contact.PermissionToCall)
{
  alert("Call " + contact.Name + " at " + contact.PhoneNumbers[0].Number);
}
Примечание.   Более подробное обсуждение поддержки литералов для JavaScript можно найти в Основном руководстве по JavaScript 1.5 в разделе Литералы.

От литералов JavaScript к JSON

JSON – это формат обмена данными, созданный из подмножества литеральной нотации для объектов в JavaScript. Хотя синтаксис, принятый в JavaScript для литеральных значений, очень гибок, важно отметить, что JSON подчиняется более строгим правилам. В соответствии со стандартом JSON, например, название члена объекта должно быть допустимой строкой JSON. Строка в JSON должна быть взята в кавычки. JavaScript, с другой стороны, позволяет ограничивать названия члена объекта кавычками или апострофами или вообще обходиться без кавычек, если название члена не конфликтует с зарезервированным ключевым словом JavaScript. Аналогично, элемент массива или значение члена объекта в JSON ограничены весьма небольшим набором. В JavaScript, тем не менее, значения элементов массива и членов объекта могут относиться к практически любому выражению JavaScript, включая вызовы функций и определения!

Очарование JSON заключается в его простоте. Сообщение, форматированное в соответствии со стандартом JSON, состоит из единственного объекта или массива верхнего уровня. Элементами массива и значениями объекта могут быть объекты, массивы, строки, числа, логические величины (истина и ложь) или пустое значение (NULL). Это, в двух словах, и есть стандарт JSON! Он действительно настолько прост. См. http://www.json.org/ или RFC 4627 для ознакомления с более формальным описанием стандарта.

Одним из больных мест JSON является отсутствие литерала даты/времени. Многие удивляются и разочаровываются, когда узнают это при первом знакомстве с JSON. Простым объяснением этому (утешительно это или нет) отсутствию литерала даты/времени является то, что в JavaScript этого литерала тоже нет: Значения даты и времени в JavaScript подставляются через объект Date. Поэтому во многих приложениях, использующих JSON, для выражения значений даты и времени обычно применяется либо строка, либо число. Если используется строка, то она обычно будет в формате ISO 8601. Если используется число, то значение обычно показывает число миллисекунд по универсальному глобальному времени (UTC) с начала эпохи, а именно с полуночи 1 января 1970 г. (UTC). Опять же, это делается исключительно для удобства и не входит в стандарт JSON. Если вы обмениваетесь данными с другим приложением, вам понадобится ознакомиться с его документацией, чтобы посмотреть, каким образом в нем кодируются значения даты и времени в рамках литерала JSON. Например, в приложениях AJAX ASP.NET Майкрософт не используется ни одно из описанных соглашений. Вместо этого в них значения .NET DateTime кодируются как строка JSON, содержимое которой представляет собой \/Date(ticks)\/, а ticks соответствуют миллисекундам с начала эпохи (UTC). Таким образом, 29 ноября 1989 г., 4:55:30 утра, в UTC кодируется следующим образом "\/Date(628318530718)\/".

AJAX ASP.NET: Внутри строки даты и времени JSON

Сериализатор JSON AJAX в ASP.NEXT кодирует экземпляр DateTime как строку JSON. Перед окончательным выпуском в AJAX ASP.NET использовался формат "@ticks@", где поле ticks представляло количество миллисекунд с 1 января 1970г. по Универсальному Глобальному Времени (UTC). Дата и время в UTC, например 29 ноября 1989 г., 4:55:30 утра, была бы написана как "@62831853071@". Несмотря на простоту, этот формат не может провести различие между датой и временем, закодированными при помощи сериализатора, и строкой, которая похожа на дату сериализатора, но не предназначена для десериализации. Группа разработчиков AJAX ASP.NET внесла изменения в последнюю версию, чтобы решить эту проблему, и ввела формат "\/Date(ticks)\/".

Новый формат использует небольшую хитрость для уменьшения шанса ошибки при интерпретации. В JSON знак прямой косой черты (/) в строке можно экранировать при помощи обратной косой черты (\), хотя это не обязательно. Воспользовавшись этим, группа разработчиков AJAX ASP.NET изменила JavaScriptSerializer, чтобы тот записывал экземпляр DateTime в виде строки "\/Date(ticks)\/". Экранирование двух прямых косых черт хотя и кажется несущественным, но является очень важным для JavaScriptSerializer. По правилам JSON "\/Date(ticks)\/" технически эквивалентно "/Date(ticks)/", но JavaScriptSerializer десериализует первое в DateTime, а второе в строку. Таким образом, возможности для неоднозначности значительно уменьшены в сравнении с более простым форматом "@ticks@" из предыдущих версий.

<!----> Сравнение JSON и XML

JSON и XML оба могут быть использованы для представления двоичных, хранящихся в памяти объектов в текстовом читаемом формате обмена данными. Более того, оба формата обмена данными сходны по структуре – при наличии текста в одном формате его эквивалент можно найти в другом. Например, при вызове одной из общедоступных веб-служб Yahoo! можно указать при помощи строкового параметра запроса, в каком формате нужно получить ответ – в XML или JSON. Таким образом при принятии решения относительно формата обмена данными предпочтение одному из форматов отдается на основании того, какой из форматов располагает характеристиками , наиболее подходящими для конкретного применения. Например, корни XML лежат в разметке текстов, следовательно он будет особенно удобен именно в этой области (что очевидно в XHTML). JSON, с другой стороны, уходит корнями в типы и структуры программных языков и, следовательно, дает более естественную и доступную возможность сопоставления структурных данных обмена. Усвоив эти основные различия, можно понять и сравнить основные характеристики XML и JSON при помощи следующей таблицы.

Основные различия характеристик XML и JSON

Характеристика XML JSON
Типы данных Не дает обозначения типа данных. Необходимо опираться на схему XML для добавления сведений о типе. Обеспечивает скалярные типы данных и возможность выражать структурированные данные посредством массивов и объектов.
Поддержка массивов Массивы должны выражаться путем соглашений, например, путем использования внешнего замещающего элемента, моделирующего содержимое массивов в качестве внутренних элементов. Обычно внешние элементы используют множественное число от названия, использованного для внешних элементов. Встроенная поддержка массивов
Поддержка объектов Объекты должны выражаться путем соглашений, часто путем комбинированного использования атрибутов и элементов. Встроенная поддержка объектов
Поддержка NULL Требует использования xsi:nil для элементов в экземпляре документа XML плюс импорта соответствующего пространства имен. Встроенное распознавание значения NULL.
Комментарии Встроенная поддержка, как правило, доступны при помощи интерфейсов API. Не поддерживаются.
Пространства имен Поддерживаются пространства имен, что уменьшает риск конфликтов имени при комбинировании документов. Пространства имен также позволяют без риска расширять существующие стандарты, основанные на XML. Нет концепции пространства имен. Риск конфликтов имени обычно избегается вкладыванием объектов или использованием префикса в названии члена объекта (более часто используется первый вариант).
Принятие решений о форматировании Сложное. Требует больших усилий для принятия решения в отношении того, как преобразовать прикладные типы в элементы и атрибуты XML. Может вызвать жаркие споры относительно того, какой подход лучше – уделяющий основное внимание элементам или атрибутам. Простое. Обеспечивает более прямое преобразование прикладных данных. Единственным исключением может являться отсутствие литерала даты/времени.
Размер Обычно документы имеют очень большой размер, особенно при использовании подхода к форматированию, уделяющего основное внимание элементам. Синтаксис очень насыщенный, а результатом является форматированный текст, большую часть которого составляют представленные данные.
Анализ в JavaScript Требует применения DOM XML и дополнительного кода приложения для преобразования текста обратно в объекты JavaScript. Для анализа текста не требуется дополнительного кода приложения; можно использовать функцию JavaScript eval.
Кривая обучения Обычно требует совместного использования нескольких технологий: XPath, схемы XML, XSLT, пространств имен XML, а также DOM, и так далее. Очень простая технология, уже известная разработчикам, работающим с JavaScript или с другими динамическими языками программирования.

JSON – это относительно новый формат обмена данными, еще не имеющий многолетнего опыта применения или технической поддержки, которая есть сегодня у XML (хотя JSON быстро движется в этом направлении). Следующая таблица показывает текущее состояние дел в области XML и JSON.

Различие в поддержке XML и JSON

Поддержка XML JSON
Средства Пользуется разработанным набором средств, имеющихся в наличии у большинства поставщиков в отрасли. Богатая поддержка средствами – включая редакторы и средства форматирования – пока встречается редко.
Microsoft .NET Framework Очень хорошая и квалифицированная поддержка, начиная с версии 1.0 .NET Framework. Поддержка XML доступна как часть Base Class Library (BCL). Для неуправляемых сред существует MSXML. Пока нет, за исключением начальной реализации в виде части AJAX ASP.NET.
Платформа и язык Средства анализа и форматирования широко доступны на многих платформах и языках (коммерческие реализации и реализации с открытым исходным кодом). Средства анализа и форматирования уже доступны на многих платформах и языках. Посетите json.org, где имеется достаточное количество справочных сведений. Большинство реализаций на сегодняшний день являются проектами с открытым исходным кодом.
Интегрированный язык В настоящее время поставщики экспериментируют с поддержкой буквально внутри языков. Для получения дополнительных сведений см. проект LINQ корпорации Майкрософт. Имеется встроенная поддержка только в JavaScript/ECMAScript.
Примечание.   Ни одна из таблиц не содержит в себе полный список характеристик для сравнения. Существует еще несколько аспектов, по которым можно сравнивать эти форматы, но мы посчитали эти основные пункты достаточными для создания общего представления.

<!----> Создание и анализ сообщений JSON при помощи JavaScript

При использовании JSON в качестве формата обмена данными имеются две общие задачи: представление двоичного объекта, существующего в оперативной памяти, в виде текста JSON и наоборот. К сожалению, на время написания этой статьи JavaScript не предлагает встроенных функций создания текста JSON из данного объекта или массива. Ожидается, что эти методы будут включены в четвертую версию стандарта ECMAScript в 2007 году. Пока же функции форматирования JSON формально не добавлены к JavaScript и не будут широко доступны в популярных реализациях, используйте образец реализации в виде сценария, который можно загрузить с http://www.json.org/json.js.

В последней версии, существующей на момент написания статьи, сценарий json.js на http://www.json.org/ добавляет функции toJSONString() к массиву, строке, логическому значению, объекту и другим типам JavaScript. Функции toJSONString() для скалярных типов (таких как числа и логические значения) являются довольно простыми, поскольку им необходимо лишь возвращать строковое представление значения экземпляра. Функция toJSONString() для логического типа, например, возвращает строку «истина», если значение истинно, и «ложь» в другом случае. Функции toJSONString()<!---->для типов массива и объекта являются более интересными. Для экземпляров массива функция toJSONString() для каждого содержащегося в нем элемента вызывается последовательно, а результаты связываются при помощи запятых, отделяющих их друг от друга. Окончательный результат заключается в квадратные скобки. Точно так же в экземплярах объекта перечисляется каждый член и вызывается его функция toJSONString(). Название члена и представление JSON его значения связываются двоеточием посредине; каждая пара из названия члена и значения отделяется от других запятыми, а окончательный результат заключается в фигурные скобки.

Общий результат функций toJSONString() заключается в том, что любой тип может быть переведен в формат JSON при помощи одного вызова функции. В следующем сценарии JavaScript создается объект массивового типа и добавляются семь элементов строкового типа с целенаправленным использованием подробного и нелитерального метода с иллюстративной целью. Далее в нем демонстрируется представление массивов в JSON:

// josn.js must be included prior to this point

var continents = new Array();
continents.push("Europe");
continents.push("Asia");
continents.push("Australia");
continents.push("Antarctica");
continents.push("North America");
continents.push("South America");
continents.push("Africa");

alert("The JSON representation of the continents array is: " +
 continents.toJSONString());

Рис. 1. Функция toJSONString() производит массив, форматированный в соответствии со стандартом JSON.

Анализ текста JSON еще более прост. Поскольку JSON – это просто подмножество литералов JavaScript, его можно проанализировать и преобразовать в представление в оперативной памяти, используя функцию eval(выражение), рассматривая исходный текст JSON в качестве исходного кода JavaScript. Функция eval принимает в качестве входа строку допустимого кода JavaScript и вычисляет выражение. Таким образом, следующая строка кода – это все, что необходимо для перевода текста JSON в двоичное представление:

var value = eval( "(" + jsonText + ")" );
Примечание.   Используются дополнительные круглые скобки для того, чтобы eval обязательно обращался с входным потоком как с выражением. Это особенно важно для объектов. Если вы попробуете вызвать eval для строки, содержащей текст JSON, определяющий объект, например "{}" (означающей пустой объект), то в результате анализа будет возвращен неопределенный результат. Круглые скобки заставляют анализатор JavaScript видеть фигурные скобки верхнего уровня как литеральную нотацию для экземпляра объекта, а не как фигурные скобки, например, определяющие блок операторов. Впрочем, этой проблемы не возникает, если объектом верхнего уровня является массив, как в eval("[1,2,3]"). Однако, в целях единообразия, текст JSON должен быть всегда заключен в круглые скобки перед вызовом eval, чтобы не возникло неопределенности относительно того, как интерпретировать исходный код.

При вычислении значения литеральной нотации экземпляр, соответствующий литеральному синтаксису, возвращается и присваивается переменной value. Посмотрите на следующий пример, использующий функцию eval для анализа литеральной нотации для массива и присваивания массива, полученного в результате, переменной continents.

var arrayAsJSONText = '["Europe", "Asia", "Australia", "Antarctica",
 "North America", "South America", "Africa"]';
var continents = eval( arrayAsJSONText );
alert(continents[0] + " is one of the " + continents.length + "
 continents.");

Разумеется, на практике определяемый текст JSON скорее будет приходить из какого-либо внешнего источника, а не будет жестко определенным, как в приведенном выше примере.

Функция eval будет просто вычислять любое переданное ей выражение. Ненадежный источник может включать в себя потенциально опасный код JavaScript сам по себе или в сочетании с литеральной нотацией, составляющей данные JSON. В ситуациях, где источник ненадежен, рекомендуется анализировать текст JSON при помощи функции parseJSON() (находится в json.js):

// Requires json.js
var continents = arrayAsJSONText.parseJSON();

Функция parseJSON() также использует eval, но только если строка, которая содержится в arrayAsJSONText соответствует текстовому стандарту JSON. Она делает это, используя сложную проверку регулярного выражения.

<!----> Работа с JSON в .NET Framework

Текст JSON легко создается и анализируется при помощи кода JavaScript, что добавляет ему привлекательности. Однако, когда JSON используется в веб-приложениях ASP.NET, только обозреватель получает поддержку JavaScript, поскольку код сервера в большинстве случаев написан на Visual Basic или C#.

Большинство библиотек Ajax, разработанных для ASP.NET, обеспечивают поддержку для программного создания и анализа текста JSON. Таким образом, если нужно работать с JSON в приложении .NET, используйте одну из этих библиотек. Существует множество вариантов с открытым исходным кодом, предлагаемых другими разработчиками, однако Майкрософт предлагает свою собственную библиотеку Ajax под названием ASP.NET AJAX.

В этой статье мы рассмотрим примеры, использующие Jayrock, реализацию JSON с открытым исходным кодом для Microsoft .NET Framework, созданную нашим соавтором Атифом Азизом. Мы выбрали Jayrock вместо AJAX ASP.NET по трем причинам:

  • Jayrock имеет открытый исходный код, поэтому его можно расширять или настраивать так, как необходимо.
  • Jayrock можно использовать в приложениях ASP.NET 1.x, 2.0, и Mono, в то время как AJAX ASP.NET предназначен только для ASP.NET версии 2.0.
  • Диапазон применения Jayrock ограничен JSON и JSON-RPC, при этом первый является основной темой этой статьи. Хотя ASP.NET AJAX включает некоторую поддержку для создания и анализа текста JSON, он в первую очередь предназначен для обеспечения платформы для построения комплексных веб-приложений стиля Ajax в ASP.NET. Дополнительные свойства могут только отвлекать, когда основное внимание должно быть уделено JSON.

Работа с JSON в .NET с использованием Jayrock аналогична работе с XML при помощи классов XmlWriter, XmlReader, и XmlSerializer в .NET Framework. Классы JsonWriter, JsonReader, JsonTextWriter, и JsonTextReader, находящиеся в Jayrock, повторяют семантику классов .NET Framework XmlWriter, XmlReader, XmlTextWriter и XmlTextReader. Эти классы используются для обеспечения взаимодействия с JSON на низком и ориентированном на поток уровне. Используя эти классы, можно создавать и анализировать текст JSON по частям при помощи ряда вызовов методов. Например, при использовании класса JsonWriter метод WriteNumber(число) создает соответствующее строковое представление числа в соответствии со стандартом JSON. Класс JsonConvert предлагает методы Export и Import для преобразования между типами .NET и JSON. Эти методы предлагают функциональность, схожую с той, что предлагается методами Serialize и Deserialize класса XmlSerializer соответственно.

Создание текста JSON

Следующий код иллюстрирует использование класса JsonTextWriter для создания текста JSON для массива строк континентов. Этот текст JSON отправляется в экземпляр TextWriter, передаваемый в конструктор, который в данном случае является выходным потоком с консоли (в ASP.NET вместо этого можно использовать Response.Output):

using (JsonTextWriter writer = JsonTextWriter(Console.Out))
{
    writer.WriteStartArray();
    writer.WriteString("Europe");
    writer.WriteString("Asia");
    writer.WriteString("Australia");
    writer.WriteString("Antarctica");
    writer.WriteString("North America");
    writer.WriteString("South America");
    writer.WriteString("Africa");
    writer.WriteEndArray();
}

Помимо методов WriteStartArray, WriteString и WriteEndArray, класс JsonWriter предлагает методы для написания других типов значений JSON, таких как WriteNumber, WriteBoolean, WriteNull и так далее. Методы WriteStartObject, WriteEndObject и WriteMember создают текст JSON для объекта. Следующий пример иллюстрирует создание текста JSON для контактного объекта, исследованного в разделе «Знакомство с литеральной нотацией в JavaScript»:

private static void WriteContact()
{
    using (JsonWriter writer = new JsonTextWriter(Console.Out))
    {
        writer.WriteStartObject();              //  {
        writer.WriteMember("Name");             //      "Name" : 
        writer.WriteString("John Doe");         //          "John Doe",
        writer.WriteMember("PermissionToCall"); //      "PermissionToCall"
 :
        writer.WriteBoolean(true);              //          true,
        writer.WriteMember("PhoneNumbers");     //      "PhoneNumbers" :
        writer.WriteStartArray();               //          [ 
        WritePhoneNumber(writer,                //            {
 "Location": "Home",
            "Home", "555-555-1234");            //              "Number":
 "555-555-1234" },
        WritePhoneNumber(writer,                //            {
 "Location": "Work",
            "Work", "555-555-9999 Ext. 123");   //              "Number":
 "555-555-9999 Ext. 123" }
        writer.WriteEndArray();                 //          ]
        writer.WriteEndObject();                //  }
    }
}

private static void WritePhoneNumber(JsonWriter writer, string location,
 string number)
{
    writer.WriteStartObject();      //  {
    writer.WriteMember("Location"); //      "Location" : 
    writer.WriteString(location);   //          "...", 
    writer.WriteMember("Number");   //      "Number" :
    writer.WriteString(number);     //          "..."
    writer.WriteEndObject();        //  }
}

Методы Export и ExportToString в классе JsonConvert можно использовать для сериализации указанного типа .NET в текст JSON. Например, вместо того чтобы вручную создавать текст JSON для массива семи континентов, используя класс JsonTextWriter, можно вызвать JsonConvert.ExportToString, что даст тот же результат:

string[] continents = {
      "Europe", "Asia", "Australia", "Antarctica", "North America", "South
 America", "Africa"
};
string jsonText = JsonConvert.ExportToString(continents);

Анализ текста JSON

Класс JsonTextReader предлагает разнообразные методы для анализа маркеров текста JSON; основным из этих методов является Read. Каждый раз при вызове метода Read анализатор получает следующий маркер, который может быть значением строки, значением числа, названием члена объекта, началом массива и так далее. При возможности можно получить доступ к анализируемому тексту текущего маркера при помощи свойства Text. Например, если программа чтения обрабатывает логические данные, то свойство Text возвратит «истина» или «ложь» в зависимости от фактически проанализированного значения.

Следующий код использует класс JsonTextReader для анализа представления массива строк в виде текста JSON, содержащего названия семи континентов. Каждый континент, название которого начинается с буквы «А», отправляется на консоль:

string jsonText = @"[""Europe"", ""Asia"", ""Australia"", ""Antarctica"",
 ""North America"", ""South America"", ""Africa""]";

using (JsonTextReader reader = new JsonTextReader(new
 StringReader(jsonText)))
{
    while (reader.Read())
    {
        if (reader.TokenClass == JsonTokenClass.String &&
            reader.Text.StartsWith("A"))
        {
            Console.WriteLine(reader.Text);
        }
    }
}
Примечание.   Класс JsonTextReader в Jayrock – довольно либеральный анализатор текста JSON. Он позволяет гораздо больше синтаксиса, чем считается допустим для текста JSON в соответствии с правилами, изложенными в RFC 4627. Например, класс JsonTextReader позволяет однострочные и многострочные комментарии внутри текста JSON, что можно ожидать в JavaScript. Однострочные комментарии начинаются с двойной косой черты (//), а многострочные комментарии – с сочетания косой черты со звездочкой (/*) и оканчиваются сочетанием звездочки с косой чертой (*/). Однострочные комментарии могут также начинаться со знака диез (#), что характерно для файлов настройки в стиле Unix. Во всех экземплярах комментарии пропускаются анализатором и никогда не показываются через интерфейс API. Также, как и в JavaScript, JsonTextReader допускает ограничение строки JSON с помощью апострофа ('). Анализатор может выдержать даже лишнюю запятую после последнего члена объекта или элемента массива.
Даже со всеми этими дополнениями JsonTextReader остается весьма адекватным анализатором! JsonTextWriter, с другой стороны, производит текст JSON, строго соответствующий стандартам. Это отвечает тому, что часто называется принципом здравомыслия, который гласит: «Будь консервативен в том, что ты делаешь, и либерален к тому, что ты принимаешь от других».

Для преобразования текста JSON непосредственно в объект .NET используйте метод импорта класса JsonConvert, указав тип результата и текст JSON. Следующий пример показывает преобразование массива строк JSON в массив строк .NET:

string jsonText = @"[""Europe"", ""Asia"", ""Australia"", ""Antarctica"",
 ""North America"", ""South America"", ""Africa""]";

string[] continents = (string[]) JsonConvert.Import(typeof(string[]),
 jsonText);

Вот более интересный пример преобразования, использующий канал RSS XML, который проходит десериализацию в тип .NET с помощью XmlSerializer. Затем объект преобразовывается в текст JSON с использованием JsonConvert (тем самым RSS в формате XML фактически преобразуется в текст JSON):

XmlSerializer serializer = new XmlSerializer(typeof(RichSiteSummary));
RichSiteSummary news;

// Get the MSDN RSS feed and deserialize it...

using (XmlReader reader = XmlReader.Create("http://msdn.microsoft.com/rss.xml"))
{
    news = (RichSiteSummary) serializer.Deserialize(reader);
}


// Export the RichSiteSummary object as JSON text, emitting the output to
 Console.Out

using (JsonTextWriter writer = new JsonTextWriter(Console.Out))
{
    JsonConvert.Export(news, writer);
}
Примечание.   Определение RichSiteSummary и соответствующих типов можно найти в примерах, сопровождающих эту статью.

Использование JSON в ASP.NET

Посмотрев на то, как происходит работа с JSON в JavaScript, а также в .NET Framework с использованием Jayrock, мы обратимся к практическому примеру того, как можно применить это знание. Рассмотрим функцию обратного вызова клиентского сценария в ASP.NET 2.0, которая упрощает процесс вызова за пределы диапазона от из обозревателя к странице ASP.NET (или определенному элементу управления на странице). Во время обычного обратного вызова клиентский сценарий в обозревателе упаковывает и отправляет данные обратно на веб-сервер для обработки методом на сервере. После получения ответных данных от сервера клиент затем использует их для обновления окна обозревателя.

Примечание.   Дополнительные сведения можно найти в журнале MSDN Magazine в статье Обратные вызовы из сценария в ASP.NET 2.0.

Трудности с обратным вызовом из клиентского сценария заключаются в том, что клиент и сервер могут передавать строку только туда и обратно. Поэтому перед отправкой информация для обмена должна быть преобразована из двоичного представления в оперативной памяти в строку, а затем после получения проанализирована из строки и преобразована обратно в двоичное представление в оперативной памяти. Функция обратного вызова из клиентского сценария в ASP.NET 2.0 не требует определенного формата строки для передаваемых данных, а также не предоставляет никакой встроенной функциональности для преобразования двоичного представления в оперативной памяти и строк; разработчик должен сам реализовать логику преобразования на основе какого-либо формата обмена данными по своему выбору.

Следующий пример демонстрирует, как использовать JSON в качестве формата обмена данными для обратного вызова из клиентского сценария. Пример состоит из страницы ASP.NET, которая использует данные из базы данных Northwind для предоставления списка категорий в раскрывающемся меню; товары выбранной категории показаны в маркированном списке (см. рис. 3). Если раскрывающееся меню изменяется клиентом, делается обратный вызов и передается массив, чьим единственным элементом является выбранный идентификатор CategoryID.

Примечание.   Мы передаем массив, который содержит выбранный идентификатор CategoryID в качестве единственного элемента (а не просто CategoryID), поскольку стандарт JSON требует, чтобы любой текст JSON имел объект или массив в качестве своей базы. Разумеется, клиенту не обязательно передавать текст JSON на сервер – этот пример мог бы просто передать выбранный CategoryID как строку. Однако мы хотели продемонстрировать пересылку текста JSON как в сообщениях запроса обратного вызова, так и в сообщениях ответа.

Следующий код в обработчике событий Page_Load настраивает веб-элемент управления Categories DropDownList так, что когда он изменяется, вызывается функция GetProductsForCategory и передается выбранное значение раскрывающихся списков. Эта функция инициализирует обратный вызов из клиентского сценария, если переданное из раскрывающегося списка значение больше нуля:

// Add client-side onchange event to drop-down list
Categories.Attributes["onchange"] = "Categories_onchange(this);";

// Generate the callback script
string callbackScript = ClientScript.GetCallbackEventReference(
    /* control        */ this, 
    /* argument       */ "'[' + categoryID + ']'", 
    /* clientCallback */ "showProducts", 
    /* context        */ "null");

// Add the Categories_onchange function
ClientScript.RegisterClientScriptBlock(GetType(),
"Categories_onchange", @"
    function Categories_onchange(sender)
    {
        clearResults();

        var categoryID = sender.value;            
        if (categoryID > 0)
        {
            " + callbackScript + @"
        }
    }", true);

Метод GetCallBackEventReference в классе ClientScriptManager, который используется для создания кода JavaScript, производящего обратный вызов, имеет следующий формат вызова:

public string GetCallbackEventReference (
    Control control,
    string argument,
    string clientCallback,
    string context,
)

Параметр argument определяет, какие данные отправляются от клиента на веб-сервер во время обратного вызова, а параметр clientCallback определяет название клиентской функции, которая будет вызвана после завершения обратного вызова (showProducts). Вызов метода GetCallBackEventReference создает следующий код JavaScript и добавляет его к обработанной разметке:

WebForm_DoCallback('__Page','[' + categoryID + 
']',showProducts,null,null,false)

'[' + categoryID + ']' -- значение, которое передается на сервер во время обратного вызова (массив с единственным элементом, categoryID), а showProducts - это функция JavaScript, которая выполняется при возвращении из обратного вызова.

Со стороны сервера метод, который выполняется в ответ на обратный вызов, использует класс JsonConvert из Jayrock для анализа входящего текста JSON и форматирования исходящего текста JSON. В частности, названия товаров, связанных с выбранной категорией, получаются и возвращаются как массив строк.

// Deserialize the JSON text into an array of integers
int[] args = (int[]) JsonConvert.Import(typeof(int[]), eventArgument);

// Read the selected CategoryID from the array
int categoryID = args[0];

// Get products based on categoryID 
NorthwindDataSet.ProductsRow[] rows = Northwind.Categories.FindByCategoryID(categoryID).GetProductsRows();

// Load the names into a string array
string[] productNames = new string[rows.Length];
for (int i = 0; i < rows.Length; i++)
{
    productNames[i] = rows[i].ProductName;
}// Serialize the string array as JSON text and return it to the clientreturn JsonConvert.ExportToString(productNames);
Примечание.   Класс JsonConvert используется дважды – для преобразования текста JSON в eventArgument в массив целых чисел, а затем для преобразования массива строк productNames в текст JSON для возвращения клиенту. В качестве альтернативы мы могли использовать здесь классы JsonReader и JsonWriter, но JsonConvert делает ту же работу не менее хорошо, когда данные относительно невелики и легко преобразовываются в существующие типы.

Когда данные возвращаются со стороны сервера, вызывается функция JavaScript, указанная в GetCallBackEventReference, и передается возвращаемое значение. Этот метод JavaScript, showProducts, начинается со ссылки на элемент <div>ProductOutput. Затем он анализирует ответ JSON и динамически добавляет в неупорядоченный список элемент списка для каждого элемента массива. Если для выбранной категории не были возвращены товары, то вместо этого демонстрируется соответствующее сообщение.

function showProducts(arg, context)
{
    // Dump the JSON text response from the server.

    document.forms[0].JSONResponse.value = arg;
    
    // Parse JSON text returned from callback.

    var categoryProducts = eval("(" + arg + ")");

    // Get a reference to the <div> ProductOutput.
    
    var output = document.getElementById("ProductOutput");

    // If no products for category, show message.
    
    if (categoryProducts.length == 0)
    {
        output.appendChild(document.createTextNode("There are no products
 for this category..."));
    }
    else
    {
        // There are products, display them in an unordered list. 
        
        var ul = document.createElement("ul");
        
        for (var i = 0; i < categoryProducts.length; i++)
        {
            var product = categoryProducts[i];
            var li = document.createElement("li");
            li.appendChild(document.createTextNode(product));
            ul.appendChild(li);
        }
        
        output.appendChild(ul);
    }
}

На рис. 2 показана последовательность событий, а на рис. 3 показан этот пример в действии; законченный код включен в загружаемый материал для этой статьи.

Рис. 2: Клиент отправляет выбранный код CategoryID как единственный элемент массива, а сервер возвращает массив связанных с ним названий товаров.

Рис. 3: Товары показываются в маркированном списке внутри выбранной категории.

<!----> Заключение

JSON – это упрощенный, основанный на тексте формат обмена данными на базе подмножества литеральной нотации из языка программирования JavaScript. Он предлагает сжатое кодирование прикладных структур данных и обычно используется в ситуациях, где возможна реализация JavaScript для одного или более приложений, обменивающихся данными, таких как веб-приложения стиля Ajax. Привлекательность JSON заключается в его простоте для ознакомления, принятия и реализации. При работе с JSON нет кривой обучения для разработчиков, уже знакомых с JavaScript и другими языками программирования с похожей поддержкой литеральной нотации (таких как Python и Ruby). Анализ текста JSON в коде JavaScript можно выполнить простым вызовом функции eval, а создание текста JSON просто элементарно при помощи json.js, предлагаемого на http://www.json.org/json.js.

Существует очень большое количество библиотек, работающих с JSON, на всех основных платформах. В этой статье мы рассмотрели Jayrock, библиотеку с открытым исходным кодом, для создания и анализа текста JSON в приложениях .NET. Jayrock может использоваться в приложениях ASP.NET 1.x, 2.0 и Mono. AJAX ASP.NET предлагает аналогичную JSON функциональность, но только для приложений ASP.NET 2.0.

Счастливого вам программирования!

Ajax или AJAX?

Термин Ajax впервые использовал Джесси Джеймс Гарретт для описания стиля веб-приложений и набора технологий для создания высоко интерактивных веб-приложений. Исторически термин Ajax распространился по сети как акроним AJAX, означающий Асинхронный JavaScript И XML. Со временем, тем не менее, было признано, что «Х» в AJAX не полностью представляет нижележащий формат данных, используемый для коммуникации с веб-сервером, поскольку большинство реализаций переключались на JSON как на более простую и эффективную альтернативу. Поэтому вместо замены акронима на что-либо вроде AJAJ, что сложно для произнесения, акроним перестали использовать, отдав предпочтение термину Ajax, а не акрониму AJAX.

В настоящее время можно видеть комбинированное использование как "AJAX", так и "Ajax", означающих одно и то же. В этой статье мы использовали «термин Ajax». Коммерческие продукты, предлагающие оболочки, которые разрешают использование приложений в стиле Ajax, обычно используют акроним для того, чтобы отличаться от аналогичного названного моющего средства, а также избежать потенциальных исков за использование торговой марки.

<!----> Ссылки

Особая благодарность

Перед тем как мы отдали эту статью в MSDN, наши добровольные помощники помогли нам выполнить проверку статьи и передали отзывы о содержании, грамматике и направлении. Основная работа была проделана Дугласом Крокфордом, Эриком Шенхольцером и Миланом Негованом.

Об авторах

Атиф Азиз – главный консультант Skybow AG, чья основная задача заключается в помощи клиентам в ознакомлении и построении решений на основе платформы разработки .NET. Атиф часто участвует в деятельности сообщества разработчиков Майкрософт, выступает на конференциях и пишет статьи для технических публикаций. Он также является спикером INETA и президентом самой большой швейцарской группы пользователей .NET. С ним можно связаться по адресу http://www.raboof.com.

Скотт Митчелл, автор шести книг по ASP/ASP.NET и основатель веб-узла 4GuysFromRolla.com, работает с веб-технологиями корпорации Майкрософт с 1998 года. Скотт – независимый консультант, преподаватель и автор книг. С ним можно связаться по электронной почте или через его блог: http://ScottOnWriting.net.



Опубликовал admin
21 Июл, Суббота 2007г.



Программирование для чайников.