Сопоставление 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]]