Поделиться через


Сопоставление JSON и XML

Модули чтения и записи, создаваемые фабрикой JsonReaderWriterFactory, обеспечивают интерфейс API XML к содержимому в формате JavaScript Object Notation (JSON, объектной нотации JavaScript). Формат JSON предусматривает кодирование данных с использованием подмножества объектных литералов JavaScript. Создаваемые этой фабрикой модули чтения и записи используются также при отправке или получении приложениями Windows Communication Foundation (WCF) JSON-содержимого с помощью элемента привязки WebMessageEncodingBindingElement или привязки WebHttpBinding.

Модуль чтения JSON при инициализации JSON-содержимым ведет себя так же, как модуль чтения текстовых XML-данных при инициализации экземпляром XML. Модуль записи JSON при получении последовательности вызовов, в результате которой модуль чтения текстовых XML-данных создает определенный экземпляр XML, записывает JSON-содержимое. В этом разделе описано сопоставление между этим экземпляром XML-данных и JSON-содержимым для использования в сложных сценариях.

При обработке внутри WCF JSON-содержимое представляется как набор сведений XML. Обычно внутреннее представление не должно заботить разработчика, поскольку сопоставление является исключительно логическим: JSON обычно не преобразуется физически в XML в памяти, равно как и XML не преобразуется в JSON. Сопоставление означает, что для обращения к JSON-содержимому используются интерфейсы API XML.

При использовании JSON в WCF обычно имеет место следующий сценарий: расширение функциональности WebScriptEnablingBehavior или расширение функциональности WebHttpBehavior автоматически подключает класс DataContractJsonSerializer, когда это необходимо. Сериализатор DataContractJsonSerializer понимает сопоставление между JSON и набором сведений XML и действует так, как будто работает непосредственно с JSON. (Можно использовать сериализатор DataContractJsonSerializer без какого-либо модуля чтения или записи XML, зная, что XML соответствует приведенному ниже сопоставлению).

В сложных сценариях может понадобиться непосредственно обратиться к приведенному ниже сопоставлению. Такие сценарии имеют место, когда требуется сериализовать десериализовать JSON особыми способами, не полагаясь на DataContractJsonSerializer, или при использовании типа Message непосредственно для сообщений, содержащих JSON. Сопоставление JSON-XML также используется для ведения журнала сообщений. При использовании функции ведения журнала сообщений в WCF сообщения JSON регистрируются в виде XML в соответствии с сопоставлением, рассмотренным в следующем разделе.

Для пояснения принципов сопоставления ниже приведен пример JSON-документа.

{"product":"pencil","price":12}

Для чтения этого JSON-документа с помощью одного из упомянутых выше модулей чтения используется та же последовательность вызовов класса XmlDictionaryReader, что и для чтения следующего XML-документа.

    <root type="object">
        <product type="string">pencil</product>
        <price type="number">12</price>
    </root>

Кроме того, если JSON-сообщение из этого примера будет получено WCF и зарегистрировано, в приведенном выше журнале будет присутствовать фрагмент XML.

Сопоставление между JSON и набором сведений XML

С формальной точки зрения, сопоставляются формат JSON, описанный в RFC 4627 (за исключением смягчения некоторых ограничений и добавления других) и набор сведений XML (не текстовые XML-данные), описанный в спецификации XML Information Set. Описания информационных единиц и полей в [квадратных скобках] можно найти в этой спецификации.

Пустой JSON-документ соответствует пустому XML-документу, а пустой XML-документ соответствует пустому JSON-документу. При сопоставлении XML-JSON пробел в начале документа и пробел в конце документа не допускаются.

Сопоставление определяется между информационной единицей документа (Document Information Item, DII) и информационной единицей элемента (Element Information Item, EII) и JSON. Информационная единица элемента (или свойство [document element] информационной единицы документа) называется корневым элементом JSON. Обратите внимание, что фрагменты документов (XML-данные с несколькими корневыми элементами) в этом сопоставлении не поддерживаются.

Пример. Как следующий документ:

<?xml version="1.0"?>

<root type="number">42</root>

так и следующий элемент:

<root type="number">42</root>

оба могут быть сопоставлены JSON. Элемент <root> является корневым элементом JSON в обоих случаях.

Кроме того, в случае DII необходимо иметь в виду следующее.

  • Некоторые элементы в списке [children] присутствовать не должны. Не следует полагаться на это при чтении XML-данных, полученных из JSON.

  • Список [children] не содержит информационных единиц комментариев.

  • Список [children] не содержит информационных единиц DTD.

  • Список [children] не содержит информационных единиц персональных данных (объявление <?xml…> не считается информационной единицей персональных данных).

  • Набор [notations] пуст.

  • Набор [unparsed entities] пуст.

Пример. Следующий документ не может быть сопоставлен JSON, поскольку список [children] содержит персональные данные и комментарий.

<?xml version="1.0"?>

<!--comment--><?pi?>

<root type="number">42</root>

EII для корневого элемента JSON имеет следующие характеристики.

  • Свойство [local name] имеет значение "root".

  • Свойство [namespace name] не имеет значения.

  • Свойство [prefix] не имеет значения.

  • Список [children] может содержать информационные единицы элементов (которые представляют внутренние элементы; см. описание ниже) или информационные единицы символов (Character Information Item, CII; см. описание ниже) либо ни то, ни другое, но не то и другое одновременно.

  • Набор [attributes] может содержать приведенные ниже необязательные информационные единицы атрибутов (Attribute Information Item, AII).

  • Атрибут типа JSON ("type") (см. описание ниже). Этот атрибут используется для сохранения типа JSON (string, number, boolean, object, array или null) в полученных в результате сопоставления XML-данных.

  • Атрибут имени контракта данных ("__type") (см. описание ниже). Этот атрибут может присутствовать только при условии, что присутствует также атрибут типа JSON и его свойство [normalized value] имеет значение "object". Этот атрибут используется сериализатором DataContractJsonSerializer для сохранения сведений о типе контракта данных — например, в случаях полиморфизма, где сериализуется производный тип и где ожидается базовый тип. Если используется не DataContractJsonSerializer, в большинстве случаев этот атрибут игнорируется.

  • Набор [in-scope namespaces] содержит привязку "xml" к "http://www.w3.org/XML/1998/namespace", как того требует спецификация наборов сведений.

  • Свойства [children], [attributes] и [in-scope namespaces] не должны содержать никаких единиц, кроме указанных выше, а свойство [namespace attributes] не должно иметь никаких членов; тем не менее, при чтении XML-данных, полученных из JSON, на это полагаться нельзя.

Пример. Следующий документ не может быть сопоставлен JSON, поскольку набор [namespace attributes] не пуст.

<?xml version="1.0"?>

<root xmlns:a="foo">42</root>

AII для атрибута типа JSON имеет следующие характеристики.

  • Свойство [namespace name] не имеет значения.

  • Свойство [prefix] не имеет значения.

  • Свойство [local name] имеет значение «type».

  • Свойство [normalized value] имеет одно из возможных значений-типов, описанных в следующем разделе.

  • Флаг [specified] имеет значение true.

  • Свойство [attribute type] не имеет значения.

  • Свойство [references] не имеет значения.

AII для атрибута имени контракта данных JSON имеет следующие характеристики.

  • Свойство [namespace name] не имеет значения.

  • Свойство [prefix] не имеет значения.

  • Свойство [local name] имеет значение «__type» (два знака подчеркивания и слово «type»).

  • Свойство [normalized value] равно любой строке Юникод — сопоставление этой строки с JSON описывается в следующем разделе.

  • Флаг [specified] имеет значение true.

  • Свойство [attribute type] не имеет значения.

  • Свойство [references] не имеет значения.

Внутренние элементы, содержащиеся в корневом элементе JSON или других внутренних элементах, имеют следующие характеристики.

  • Свойство [local name] может иметь одно из описанных ниже значений.

  • Свойства [namespace name], [prefix], [children], [attributes], [namespace attributes] и [in-scope namespaces] подчиняются тем же правилам, что и корневой элемент JSON.

И в корневом элементе JSON, и во внутренних элементах атрибут типа JSON определяет сопоставление с JSON, возможные дочерние информационные единицы ([children]) и их интерпретацию. В нормализованном значении атрибута (свойство [normalized value]) учитывается регистр; оно должно быть в нижнем регистре и не должно содержать пробелов.

Нормализованное значение AII атрибута типа JSON (JSON Type Attribute) Допустимые дочерние информационные единицы соответствующей EII Сопоставление с JSON

string (или отсутствие AII типа JSON)

string и отсутствие AII типа JSON — одно и то же, поэтому string используется по умолчанию.

Следовательно, <root> string1</root> соответствует string "string1" в JSON.

0 или более CII

Фрагмент JSON типа string (RFC по JSON, раздел 2.5). Каждый фрагмент типа char — это символ, соответствующий свойству [character code] из CII. Если CII нет, он сопоставляется пустому фрагменту JSON типа string.

Пример. Следующий элемент сопоставляется фрагменту JSON:

<root type="string">42</root>

Фрагмент JSON: "42".

При сопоставлении XML-JSON символы, которые должны быть снабжены escape-знаком, сопоставляются символам с escape-знаком, все остальные символы сопоставляются символам без escape-знака. Символ "/" является специальным — он предваряется escape-знаком, хотя и не должен (записывается как "\/").

Пример. Следующий элемент сопоставляется фрагменту JSON:

<root type="string">the "da/ta"</root>

Фрагмент JSON: "the \"da\/ta\"".

При сопоставлении JSON-XML символы с escape-знаком и символы без escape-знака корректно сопоставляются соответствующему свойству [character code].

Пример. Фрагмент JSON "\u0041BC" сопоставляется следующему XML-элементу:

<root type="string">ABC</root>

Строка может быть окружена пробелами ("ws" в разделе 2 RFC по JSON), которые не сопоставляются с XML.

Пример. Фрагмент JSON "ABC" (с пробелами перед первой двойной кавычкой) сопоставляется следующему XML-элементу:

<root type="string">ABC</root>

Любой пробел в XML сопоставляется с пробелом в JSON.

Пример. Следующий XML-элемент сопоставляется фрагменту JSON:

<root type="string">  A BC      </root>

Фрагмент JSON: " A BC ".

number

1 или более CII

Фрагмент JSON типа number (RFC по JSON, раздел 2.4), возможно, окруженный пробелами. Каждый символ в комбинации число/пробел — это символ, соответствующий свойству [character code] из CII.

Пример. Следующий элемент сопоставляется фрагменту JSON:

<root type="number">    42</root>

Фрагмент JSON: 42

(Пробелы сохраняются.)

boolean

4 или 5 CII (что соответствует true или false), возможно, окруженные дополнительными CII-пробелами.

Последовательность CII, соответствующая строке "true", сопоставляется литералу true, а последовательность CII, соответствующая строке "false", сопоставляется литералу false. Окружающие пробелы сохраняются.

Пример. Следующий элемент сопоставляется фрагменту JSON:

<root type="boolean"> false</root>

Фрагмент JSON: false.

null

Не допускается ни одного.

Литерал null. При сопоставлении JSON-XML фрагмент null может быть окружен пробелами ("ws" в разделе 2), которые не сопоставляются с XML.

Пример. Следующий элемент сопоставляется фрагменту JSON:

<root type="null"/>

или

<root type="null"></root>

:

Фрагмент JSON в обоих случаях — Null.

object

0 или более EII.

Фрагмент begin-object (левая фигурная скобка), согласно разделу 2.2 RFC по JSON, после которой идет запись-член для каждой EII, как описано ниже. Если EII больше одной, между записями-членами ставятся разделители значений (запятые). После этого идет фрагмент end-object (правая фигурная скобка).

Пример. Следующий элемент сопоставляется фрагменту JSON:

<root type="object">

<type1 тип="string">aaa</type1>

<type2 тип="string">bbb</type2>

</root >

Фрагмент JSON: {"type1":"aaa","type2":"bbb"}.

Если в сопоставлении XML-JSON присутствует атрибут типа контракта данных, в начале вставляется дополнительная запись-член. Имя этой записи — локальное имя (свойство [local name]) атрибута типа контракта данных ("__type"), а ее значение — нормализованное значение (свойство [normalized value]) атрибута. И наоборот, при сопоставлении JSON-XML, если имя первой записи-члена представляет собой локальное имя атрибута типа контракта данных (т. е. "__type"), в полученном XML присутствует соответствующий атрибут типа контракта данных, однако соответствующая EII отсутствует. Обратите внимание, что для применения этого особого сопоставления эта запись-член должна идти первой в объекте JSON. Это отход от обычной обработки JSON, где порядок записей-членов не имеет значения.

Пример.

Следующий фрагмент JSON сопоставляется XML.

{"__type":"Person","name":"John"}

XML представляет собой следующий код.

<root type="object" __type="Person">
  <name type="string">John</name>
</root>

Обратите внимание, что AII __type присутствует, однако EII __type — нет.

Однако если порядок в JSON будет обратным, как показано в следующем примере:

{"name":"John","__type":"Person"}

соответствующий XML-код будет выглядеть так:

<root type="object">
  <name type="string">John</name>
  <__type type="string">Person</__type>
</root>

Таким образом, __type теряет особое значение и сопоставляется EII, как обычно, а не AII.

Правила добавления/удаления escape-знаков для свойства [normalized value] AII при сопоставлении значению JSON такие же, как и для строк JSON (см. строку "string" выше в таблице).

Пример.

<root type="object" __type="\abc" />

Предыдущий пример может быть сопоставлен следующему фрагменту JSON.

{"__type":"\\abc"}

При сопоставлении XML-JSON свойство [local name] первой EII не должно иметь значения "__type".

Пробелы (ws) никогда не создаются для объектов при сопоставлении XML-JSON и не учитываются при сопоставлении JSON-XML.

Пример. Следующий фрагмент JSON сопоставляется XML-элементу:

{ "ccc" : "aaa", "ddd" :"bbb"}

XML-элемент показан в следующем коде.

<root type="object">
   <ccc type="string">aaa</ccc>
   <ddd type="string">bbb</bar>
</root >

array

0 или более EII

Фрагмент begin-array (левая квадратная скобка), согласно разделу 2.3 RFC по JSON, после которой идет запись-массив для каждой EII, как описано ниже. Если EII больше одной, между записями-массивами ставятся разделители значений (запятые). После этого идет фрагмент end-array.

Пример. Следующий XML-элемент сопоставляется фрагменту JSON:

<root type="array"/>
   <item type="string">aaa</item>
   <item type="string">bbb</item>
</root >

Фрагмент JSON: ["aaa","bbb"]

Пробелы (ws) никогда не создаются для массивов при сопоставлении XML-JSON и игнорируются при сопоставлении JSON-XML.

Пример. Фрагмент JSON:

[ "aaa", "bbb"]

XML-элемент, которому он сопоставляется:

<root type="array"/>
   <item type="string">aaa</item>
   <item type="string">bbb</item>
</root >

Записи-члены работают следующим образом.

  • Свойство [local name] внутреннего элемента сопоставляется string-части фрагмента member, согласно 2.2 RFC по JSON.

Пример. Следующий элемент сопоставляется фрагменту JSON:

<root type="object"/>

<myLocalName type="string">aaa</myLocalName>

</root >

Получается следующий фрагмент JSON:

{"myLocalName":"aaa"}

  • При сопоставлении XML-JSON символы, которые в JSON должны быть снабжены escape-знаком, предваряются escape-знаком, остальные символы — нет. Символ "/", хотя и не является требующим escape-знака символом, тем не менее предваряется escape-знаком (при сопоставлении JSON-XML предварять escape-знаком его не нужно). Это необходимо для поддержки формата AJAX ASP.NET для данных типа DateTime в JSON.

  • При сопоставлении JSON-XML все символы (включая символы без escape-знака, если необходимо) используются для формирования фрагмента типа string, который представляет собой значение свойства [local name].

  • Внутренние элементы (список [children]) сопоставляются значению в разделе 2.2, в соответствии с атрибутом типа JSON (JSON Type Attribute), аналогично корневому элементу JSON (Root JSON Element). Несколько уровней вложения EII (включая вложения в массивах) допустимы.

Пример. Следующий элемент сопоставляется фрагменту JSON:

<root type="object">

<myLocalName1 type="string">myValue1</myLocalName1>

<myLocalName2 type="number">2</myLocalName2>

<myLocalName3 type="object">

<myNestedName1 type="boolean">true</myNestedName1>

<myNestedName2 type="null"/>

</myLocalName3>

</root >

В результате получается следующий фрагмент JSON:

{"myLocalName1":"myValue1","myLocalName2":2,"myLocalName3":{"myNestedName1":true,"myNestedName2":null}}

Bb924435.note(ru-ru,VS.100).gifПримечание
В показанном выше сопоставлении отсутствует этап XML-кодирования. Следовательно, WCF поддерживает только JSON-документы, где все символы в именах ключей представляют собой допустимые символы для имен XML-элементов. Например, JSON-документ {"<":"a"} не поддерживается, поскольку символ < не является допустимым именем для XML-элемента.

Обратная ситуация (символы, допустимые в XML, но недопустимые в JSON) никаких проблем не вызывает, поскольку описанное выше сопоставление предусматривает добавление или удаление escape-символов JSON.

Записи-массивы работают следующим образом.

  • Свойство [local name] внутреннего элемента имеет значение «item».

  • Список [children] внутреннего элемента сопоставляется значению в разделе 2.3, в соответствии с атрибутом типа JSON, как и для корневого элемента JSON. Несколько уровней вложения EII (включая вложения в объектах) допустимы.

Пример. Следующий элемент сопоставляется фрагменту JSON:

<root type="array"/>

<item type="string">myValue1</item>

<item type="number">2</item>

<item type="array">

<item type="boolean">true</item>

<item type="null"/>

</item>

</root >

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

["myValue1",2,[true,null]]

См. также

Справочник

JsonReaderWriterFactory
DataContractJsonSerializer

Основные понятия

Изолированная сериализация JSON