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

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

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

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

Если WCF использует JSON, обычный сценарий заключается в том, что DataContractJsonSerializer он автоматически подключается WebScriptEnablingBehavior к поведению или WebHttpBehavior по поведению при необходимости. Сериализатор 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-наборе сведений. В этом разделе приведены определения информационных элементов и полей в [квадратных скобках].

Пустой документ 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, в большинстве случаев этот атрибут игнорируется.

  • [в область пространствах имен] содержит привязку xml к http://www.w3.org/XML/1998/namespace спецификации infoset.

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

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

<?xml version="1.0"?>
<root xmlns:a="myattributevalue">42</root>

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

  • Свойство [namespace name] не имеет значения.
  • Свойство [prefix] не имеет значения.
  • Свойство [local name] имеет значение «type».
  • Свойство [normalized value] имеет одно из возможных значений-типов, описанных в следующем разделе.
  • Флаг [specified] имеет значение true.
  • Свойство [attribute type] не имеет значения.
  • Свойство [references] не имеет значения.

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

  • Свойство [namespace name] не имеет значения.
  • Свойство [prefix] не имеет значения.
  • [локальное имя] — "__type" (два символа подчеркивания и "тип").
  • Свойство [normalized value] равно любой строке Юникод - сопоставление этой строки с JSON описывается в следующем разделе.
  • Флаг [specified] имеет значение true.
  • Свойство [attribute type] не имеет значения.
  • Свойство [references] не имеет значения.

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

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

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

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

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

Следовательно, <root> string1</root> соответствует string "string1" в JSON.
0 или более CIIs Фрагмент 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-символа. Символ "/" является особенным - он экранируется, даже если он не должен быть (написан как "\/").

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

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

Фрагмент JSON — "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 (JSON RFC, раздел 2.4), возможно, окруженный пробелом. Каждый символ в сочетании чисел и пробелов — это символ, соответствующий [коду символов] из CII.

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

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

Фрагмент JSON: 42

(Пробел сохраняется).
boolean 4 или 5 CIIs (которые соответствуют true или false), возможно, окружены дополнительными API пробелов. Последовательность 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"/>

or

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

:

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

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

<root type="object">

<type1 type="string">aaa\</type1>

<type2 type="string">bbb\</type2>

</root >

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

Если в сопоставлении XML-JSON присутствует атрибут типа контракта данных, в начале вставляется дополнительная запись-член. Его имя — это [локальное имя] атрибута типа контракта данных ("__type"), а его значение — это [нормализованное значение] атрибута. И наоборот, в сопоставлении 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>

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

Однако если порядок в 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 первый 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}}

Примечание.

В показанном выше сопоставлении отсутствует этап 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]]

См. также