Автономная сериализация JSON с помощью DataContractJsonSerializer
Примечание.
В этой статье описано DataContractJsonSerializer. В большинстве сценариев, связанных с сериализированием и десериализацией JSON, рекомендуется использовать API в пространстве имен System.Text.Json.
JSON (JavaScript Object Notation, объектная нотация JavaScript) - формат данных, предназначенный специально для использования JavaScript-кодом, выполняемым на веб-страницах внутри браузера. Это формат данных по умолчанию, используемый службами AJAX ASP.NET, созданными в Windows Communication Foundation (WCF).
Его также можно использовать при создании служб AJAX без интеграции с ASP.NET; в данном случае форматом по умолчанию является XML, однако можно выбрать и JSON.
Наконец, если требуется поддержка JSON, однако создаваемая служба не является службой AJAX, сериализатор DataContractJsonSerializer позволяет непосредственно сериализовать объекты .NET в данные JSON и десериализовать такие данные обратно в экземпляры типов .NET. Описание этого действия см. в разделе "Практическое руководство. Сериализация и десериализация данных JSON".
При работе с JSON поддерживаются те же (за некоторыми исключениями) типы .NET, что поддерживаются сериализатором DataContractSerializer. Список поддерживаемых типов см. в разделе "Типы, поддерживаемые сериализатором контракта данных". К ним относится большинство примитивных типов, большинство типов массивов и коллекций, а также сложные типы, в которых используются атрибуты DataContractAttribute и DataMemberAttribute.
Сопоставление типов .NET с типами JSON
В следующей таблице показано соответствие между типами .NET и типами JSON/JavaScript, используемое при сопоставлении в процедурах сериализации и десериализации.
Типы .NET | JSON/JavaScript | Примечания. |
---|---|---|
Все числовые типы, например Int32, Decimal или Double | Число | Специальные значения, такие как Double.NaN , Double.PositiveInfinity и Double.NegativeInfinity , не поддерживаются и приводят к получению недопустимых JSON-данных. |
Enum | Число | См. раздел "Перечисления и JSON" далее в этой статье. |
Boolean | Логический | |
String, Char | Строка | |
TimeSpan, , GuidUri | Строка | Формат этих типов в ФОРМАТЕ JSON совпадает с форматом XML (по сути, диапазон времени в формате длительности ISO 8601, GUID в формате "12345678-ABCD-ABCD-ABCD-1234567890AB" и URI в естественной строковой форме "http://www.example.com" ). Подробные сведения см. в справочнике по схеме контракта данных. |
XmlQualifiedName | Строка | Формат - «имя:пространство_имен» (все до первого двоеточия является именем). Имя или пространство имен может отсутствовать. При отсутствии пространства имен можно также опустить двоеточие. |
Array типа Byte | Массив чисел | Каждое число представляет значение одного байта. |
DateTime | DateTime или String | См. статью "Даты и время" и JSON далее в этой статье. |
DateTimeOffset | Сложный тип | См. статью "Даты и время" и JSON далее в этой статье. |
Типы XML и ADO.NET (XmlElement, XElement. Массивы XmlNode, ISerializable, DataSet). |
Строка | См. раздел "Типы XML" и "JSON" этой статьи. |
DBNull | Пустой сложный тип | -- |
Коллекции, словари и массивы | Массив | См. раздел «Коллекции, словари и массивы» ниже. |
Сложные типы (с примененным атрибутом DataContractAttribute или SerializableAttribute) | Сложный тип | Элементы данных становятся элементами сложного типа JavaScript. |
Сложные типы (реализующие интерфейс ISerializable) | Сложный тип | То же, что и другие сложные типы, но некоторые ISerializable типы не поддерживаются, см. раздел поддержки ISerializable. |
Значение Null для любого типа |
Null | Типы значений, допускающие значение NULL, также поддерживаются и сопоставляются с JSON так же, как и типы значений, не допускающие значения NULL. |
Перечисления и JSON
Значения элементов перечислений в JSON рассматриваются как числа в отличие от контрактов данных, куда они включаются как имена элементов. Дополнительные сведения об обработке контракта данных см. в разделе "Типы перечисления" в контрактах данных.
Например, в случае перечисления
public enum Color {red, green, blue, yellow, pink}
при сериализации членаyellow
получается число 3, а не строка "yellow".Все члены типа
enum
сериализуемы. Атрибуты EnumMemberAttribute и NonSerializedAttribute (если они используются) игнорируются.Также возможна десериализация несуществующего значения
enum
- например, значение 87 можно десериализовать в упомянутое выше перечисление Color, даже несмотря на отсутствие соответствующего определенного имени цвета.Флаговый тип
enum
не является особенным и рассматривается так же, как любой другой типenum
.
Даты и время и JSON
Формат JSON не предусматривает непосредственной поддержки дат и времен. Тем не менее, они очень часто используются, и в ASP.NET AJAX предусмотрена особая поддержка для этих типов. При использовании прокси-объектов ASP.NET AJAX тип DateTime в .NET полностью соответствует типу DateTime
в JavaScript.
Если ASP.NET не используется, тип DateTime представляется в JSON в виде строки особого формата, который описан в разделе "Дополнительные сведения для опытных пользователей" ниже.
DateTimeOffset представляется в JSON как сложный тип: {"DateTime":dateTime,"OffsetMinutes":offsetMinutes}. Член
offsetMinutes
- это смещение местного времени относительно времени по Гринвичу (GMT, теперь также называемого временем в формате UTC), связанное с местоположением интересующего события. ЭлементdateTime
представляет момент во времени, когда произошло интересующее событие (опять этот элемент становится типомDateTime
в JavaScript, когда используется ASP.NET AJAX, и строкой, когда ASP.NET AJAX не используется). При сериализации членdateTime
всегда сериализуется в GMT. Так, если описывается время 3:00 по Нью-Йорку, компонентом времени членаdateTime
будет "8:00", а смещение в минутахoffsetMinutes
составит 300 (минус 300 минут, или 5 часов, относительно GMT).Примечание.
В объектах DateTime и DateTimeOffset при сериализации в JSON информация сохраняется с точностью только до миллисекунд. Значения меньше миллисекунды (микро- и наносекунды) при сериализации теряются.
Типы XML и JSON
Типы XML становятся строками JSON.
Например, если элемент данных "q" типа XElement содержит <abc/>, json имеет значение {"q":"<abc/>"}.
Существуют некоторые специальные правила, определяющие способ упаковки XML- дополнительные сведения см. в разделе "Дополнительные сведения" далее в этой статье.
При использовании ASP.NET AJAX, если вместо строк JavaScript требуется использовать модель DOM XML, присвойте значение «XML» свойству ResponseFormat в атрибуте WebGetAttribute или свойству ResponseFormat в атрибуте WebInvokeAttribute.
Коллекции, словари и массивы
Все коллекции, словари и массивы представляются в JSON в виде массивов.
Все пользовательские типы с атрибутом CollectionDataContractAttribute в JSON-представлении игнорируются.
Словари не являются способом непосредственной работы с JSON. Строка словаря<, объект> может не поддерживаться так же, как и в WCF, как ожидалось от работы с другими технологиями JSON. Например, если в словаре строка "abc" сопоставлена строке "xyz", а строка "def" строке 42, JSON-представление будет иметь вид не {"abc":"xyz","def":42}, а [{"Key":"abc","Value":"xyz"},{"Key":"def","Value":42}].
Если требуется работать непосредственно с JSON (обращаться к ключам и значениям динамически, без предварительного определения жесткого контракта), можно рассмотреть следующие варианты.
Рекомендуется использовать пример сериализации JSON с слабо типизированным типом (AJAX ).
Использование интерфейса ISerializable и конструкторов десериализации - эти два механизма позволяют обращаться к парам "ключ-значение" JSON при сериализации и десериализации соответственно, однако не работают в сценариях с частичным доверием.
Рекомендуется работать с сопоставлением МЕЖДУ JSON и XML вместо использования сериализатора.
Полиморфизм в контексте сериализации относится к возможности сериализации производного типа, в котором ожидается базовый тип. Существуют особые (только для JSON) правила, применяющиеся при полиморфном использовании коллекций, например при присвоении коллекции объекту Object. Эта проблема более подробно рассматривается в разделе "Дополнительные сведения" далее в этой статье.
Дополнительные сведения
Порядок членов данных
Порядок членов данных при использовании JSON не имеет значения. В частности, даже если задан атрибут Order, JSON-данные все равно можно сериализовать в любом порядке.
Типы JSON
Тип JSON при десериализации не обязательно должен соответствовать приведенной выше таблице. Например, тип Int
обычно сопоставляется числу JSON, однако может быть успешно десериализован из строки JSON, при условии, что строка содержит допустимое число. То есть, и {"q":42}, и {"q":"42"} допустимы, если имеется член данных типа Int
с именем "q".
Полиморфизм
Полиморфная сериализация состоит в возможности сериализовать производный тип там, где ожидается его базовый тип. Это поддерживается для сериализации JSON WCF, сравнимой с тем, как поддерживается сериализация XML. Например, можно сериализовать место ожидания или сериализовать MyDerivedType
Int
MyBaseType
, где Object
ожидается.
При десериализации производного типа там, где ожидается базовый тип, информация типа может быть потеряна, за исключением случаев десериализации сложных типов. Например, при сериализации типа Uri там, где ожидается тип Object, будет получена строка JSON. Если эту строку затем десериализовать обратно в тип Object, будет возвращен .NET-тип String. Десериализатор не знает, что строка изначально имела тип Uri. Как правило, когда ожидается тип Object, все строки JSON десериализуются как строки .NET, а все массивы JSON, используемые для сериализации коллекций, словарей и массивов .NET, десериализуются как .NET-объекты Array типа Object, вне зависимости от того, какими были исходные типы. Логический тип JSON сопоставляется .NET-типу Boolean. Однако, когда ожидается тип Object, числа JSON десериализуются в .NET-типы Int32, Decimal или Double (наиболее подходящий тип выбирается автоматически).
При десериализации в тип интерфейса DataContractJsonSerializer выполняет десериализацию так, как будто объявленный тип - объект.
При работе со своими собственными базовыми и производными типами обычно требуется использовать атрибуты KnownTypeAttribute, ServiceKnownTypeAttribute или эквивалентный механизм. Например, если у вас есть операция с Animal
возвращаемым значением, и она фактически возвращает экземпляр Cat
(производный Animal
от), следует применить KnownTypeAttributeAnimal
тип или ServiceKnownTypeAttribute операцию и указать Cat
тип в этих атрибутах. Дополнительные сведения см. в разделе "Известные типы контракта данных".
Дополнительные сведения о работе полиморфной сериализации и обсуждении некоторых ограничений, которые должны соблюдаться при использовании, см. в разделе "Дополнительные сведения" далее в этой статье.
Управление версиями
Возможности управления версиями контрактов данных, включая интерфейс IExtensibleDataObject, полностью поддерживаются в JSON. Кроме того, в большинстве случаев можно десериализовать тип в один формат (например, XML) и затем сериализовать его в другой формат (например, JSON) и при этом сохранить данные в IExtensibleDataObject. Дополнительные сведения о создании контрактов данных, обладающих прямой совместимостью, см. в разделе Контракты данных, совместимые с любыми будущими изменениями. Следует помнить, что JSON не придает значения порядку, поэтому любая информация о порядке будет потеряна. Кроме того, JSON не поддерживает множественные пары "ключ/значение" с одним и тем же именем ключа. Наконец, все операции над объектом IExtensibleDataObject по своей природе полиморфны - то есть, их производные типы присваиваются типу Object, базовому типу для всех типов.
JSON в URL-адресах
При использовании конечных точек ASP.NET AJAX с командой GET HTTP (с помощью атрибута WebGetAttribute), входящие параметры присутствуют в URL-адресе запроса, а не в теле сообщения. JSON поддерживается даже в URL-адресе запроса, поэтому если у вас есть операция с Int
именем "число" и сложный Person
тип "p", URL-адрес может выглядеть следующим образом.
http://example.com/myservice.svc/MyOperation?number=7&p={"name":"John","age":42}
При использовании диспетчера скриптов ASP.NET AJAX и прокси-объекта для вызова службы этот URL-адрес автоматически формируется прокси-объектом, и увидеть его нельзя. JSON нельзя использовать в URL-адресах на конечных точках, не являющихся конечными точками ASP.NET AJAX.
Дополнительные сведения
Поддержка интерфейса ISerializable
Поддерживаемые и неподдерживаемые типы ISerializable
Как правило, типы, реализующие интерфейс ISerializable, полностью поддерживаются при сериализации/десериализации JSON. Однако некоторые из этих типов (включая некоторые типы платформы .NET Framework) реализованы так, что некоторые аспекты, присущие именно сериализации в JSON, не позволяют им правильно десериализоваться:
При использовании интерфейса ISerializable тип отдельных членов данных никогда не известен заранее. Это ведет к полиморфной ситуации, аналогичной десериализации типов в объект. Как уже говорилось, это может привести к потере информации типов в JSON. Например, если тип сериализует в своей реализации
enum
тип ISerializable, попытка десериализовать данные обратно вenum
(без надлежащих приведений) завершится неудачей, поскольку типenum
сериализуется в JSON в виде чисел, а числа JSON десериализуются во встроенные числовые типы .NET (Int32, Decimal или Double). Поэтому тот факт, что число когда-то было значением перечисления (enum
), теряется.Тип с интерфейсом ISerializable, конструктор десериализации которого основан на определенном порядке десериализации, также может выдать ошибку при десериализации некоторых JSON-данных, поскольку большинство сериализаторов JSON не гарантируют никакого определенного порядка.
Типы производства
В то время как интерфейс IObjectReference в общем случае поддерживается в JSON, все типы, требующие возможности "типа производства" (возвращения методом GetRealObject(StreamingContext) экземпляра типа, отличного от типа, реализующего интерфейс), не поддерживаются.
Формат DateTime при передаче по линиям связи
Значения типа DateTime представляются строками JSON вида "/Date(700000+0500)/", где первое число (в данном случае 700000) - это число миллисекунд в часовом поясе GMT по обычному (не летнему) времени, прошедшее с 1 января 1970 г. Это число может быть отрицательным для представления более раннего времени. Часть строки "+0500" является необязательной и показывает, что это время в формате Local, т. е. при десериализации оно должно быть преобразовано в местный часовой пояс. Если эта часть строки отсутствует, время десериализуется как Utc. Собственно число (в данном случае "0500") и его знак (+ или -) игнорируются.
При сериализации времен формата DateTime, Local и Unspecified времена записываются со смещением, а время формата Utc записывается без смещения.
JavaScript-код клиента ASP.NET AJAX автоматически преобразует такие строки в экземпляры DateTime
JavaScript. При наличии других строк аналогичного вида, не принадлежащих к типу DateTime в .NET, они также преобразуются.
Преобразование выполняется только в том случае, если экранируются символы /" (т. е. json выглядит как \/Date(700000+0500)\/), и по этой причине кодировщик JSON WCF (включено в формате WebHttpBinding) всегда экранирует символ "/".
XML-данные в строках JSON
XmlElement
Тип XmlElement сериализуется "как есть", без оболочки. Например, член данных "x" типа XmlElement , содержащего <abc/,> представлен следующим образом:
{"x":"<abc/>"}
Массивы типа XmlNode
Объекты Array типа XmlNode помещаются в элемент-оболочку ArrayOfXmlNode в стандартном пространстве имен контракта данных для данного типа. Если "x" - массив, содержащий узел атрибута "N" в пространстве имен "ns", который содержит "value", и пустой узел элемента "M", представление выглядит следующим образом.
{"x":"<ArrayOfXmlNode xmlns=\"http://schemas.datacontract.org/2004/07/System.Xml\" a:N=\"value\" xmlns:a=\"ns\"><M/></ArrayOfXmlNode>"}
Атрибуты в пустом пространстве имен в начале массивов XmlNode (перед другими элементами) не поддерживаются.
Типы IXmlSerializable, включая XElement и DataSet
Типы ISerializable делятся на "типы содержимого", "типы DataSet" и "типы элементов". Определения этих типов см. в разделе XML и ADO.NET типов в контрактах данных.
Типы содержимого и типы "DataSet" сериализуются аналогично объектам Array типа XmlNode, рассмотренным в предыдущем разделе. Они помещаются в элемент-оболочку, имя и пространство имен которого соответствует имени контракта данных и пространству имен сериализуемого типа.
Типы элементов, такие как XElement сериализуются как есть, аналогичные XmlElement ранее рассмотренным в этой статье.
Полиморфизм
Сохранение информации типов
Как уже говорилось, полиморфизм поддерживается в JSON с некоторыми ограничениями. JavaScript - слабо типизированный язык, и идентификация типа обычно не представляет проблем. Однако при использовании JSON для обмена данными между строго типизированной системой (.NET) и слабо типизированной системой (JavaScript) полезно сохранить удостоверение типа. Например, типы с именами контрактов данных "Square" и "Circle" наследуют от типа с именем контракта данных "Shape". Если значение Circle передается из .NET в JavaScript и возвращается в метод .NET, ожидающий тип Shape, то в компоненте .NET желательно знать, что данный объект изначально принадлежал к типу Circle; в противном случае может быть потеряна информация, присутствующая только в производном типе (например, элемент данных radius в типе Circle).
Для сохранения удостоверения типа при сериализации в JSON сложных типов можно добавить "намек на тип", чтобы десериализатор распознавал этот намек и действовал соответствующим образом. "указание типа" — это пара "ключ-значение JSON" с именем ключа "__type" (два символа подчеркивания, за которым следует слово "тип"). Значение представляет собой строку JSON вида "DataContractName:DataContractNamespace" (все до первого двоеточия является именем). Продолжая предыдущий пример, тип "Circle" можно сериализовать следующим образом.
{"__type":"Circle:http://example.com/myNamespace","x":50,"y":70,"radius":10}
Намек на тип очень похож на атрибут xsi:type
, определенный в стандарте XML Schema Instance и используемый при сериализации/десериализации XML.
Элементы данных, называемые "__type", запрещены из-за потенциального конфликта с указанием типа.
Уменьшение размера намеков на тип
Чтобы уменьшить размер сообщений JSON, префикс пространства имен контракта данных поhttp://schemas.datacontract.org/2004/07/
умолчанию заменяется символом #. (Чтобы сделать эту замену обратимой, используется правило экранирования: если пространство имен начинается с символов "#" или "\", они добавляются с дополнительным символом "\"). Таким образом, если "Circle" является типом в пространстве имен .NET "MyApp.Shapes", то по умолчанию используется http://schemas.datacontract.org/2004/07/MyApp
пространство имен контракта данных. Shapes, а его JSON-представление будет иметь следующий вид.
{"__type":"Circle:#MyApp.Shapes","x":50,"y":70,"radius":10}
По десериализации понимаются как усеченные (#MyApp.Shapes), так и полные (http://schemas.datacontract.org/2004/07/MyApp.Shapes
) имена.
Положение намека на тип в объектах JSON
Обратите внимание, что намек на тип в JSON-представлении должен стоять на первом месте. Это единственный случай, когда порядок пар "ключ/значение" в обработке JSON имеет значение. Например, следующий способ задания намека на тип допустимым не является.
{"x":50,"y":70,"radius":10,"__type":"Circle:#MyApp.Shapes"}
Как используемые WCF, так и ASP.NET клиентские DataContractJsonSerializer страницы AJAX всегда выдают подсказку типа.
Намеки на тип применяются только к сложным типам
Способа выдавать намек на тип для несложных типов не существует. Например, если операция имеет тип возвращаемого значения Object, однако возвращает тип "Circle", JSON-представление может выглядеть так, как показано выше, и информация типа сохраняется. Однако если возвращается универсальный код ресурса (URI), JSON-представление будет строкой, и тот факт, что строка используется для представления URI, теряется. Это относится не только к примитивным типам, но также к коллекциям и массивам.
Когда выдается намеки на тип
Намеки на тип могут значительно увеличить размер сообщения (один из способов борьбы с этим - использовать более короткие пространства имен контрактов данных, если это возможно). По этой причине выдача намеков на тип подчиняется следующим правилам.
При использовании ASP.NET AJAX намеки на тип выдаются всегда, когда это возможно, даже при отсутствии присвоения базовый/производный - например, даже если тип "Circle" присваивается типу "Circle". (Это необходимо для полного включения процесса вызова из слабо типизированной среды JSON в строго типизированную среду .NET без удивительной потери информации.)
При использовании служб AJAX без интеграции с ASP.NET намеки на тип выдаются только при наличии присвоения базовый/производный - т. е. когда тип "Circle" присваивается типу "Shape" или типу Object, но не при присвоении типа "Circle" типу "Circle". Это минимум информации, необходимый для правильной реализации клиента JavaScript, что повышает производительность, но не защищает от потери информации о типах в неправильно спроектированных клиентах. Избегайте присвоений базовый/производный на сервере в принципе, чтобы избежать необходимости решения этой проблемы на клиенте.
При использовании типа DataContractSerializer параметр конструктора
alwaysEmitTypeInformation
позволяет выбрать один из двух упомянутых выше режимов; по умолчанию используется значение "false
" (выдавать намеки на тип только тогда, когда это необходимо).
Повторяющиеся имена членов данных
Информация производного типа присутствует в одном объекте JSON вместе с информацией базового типа и может следовать в любом порядке. Например, Shape
можно представить следующим образом.
{"__type":"Shape:#MyApp.Shapes","x":50,"y":70}
При этом тип "Circle" может быть представлен следующим образом.
{"__type":"Circle:#MyApp.Shapes","x":50, "radius":10,"y":70}
Если базовый Shape
тип также содержал элемент данных с именем "radius
", это приводит к столкновению при сериализации (так как объекты JSON не могут иметь повторяющиеся имена ключей) и десериализации (поскольку неясно, относится ли "radius" или Circle.radius
Shape.radius
). Следовательно, тогда как использовать принцип "сокрытия свойств" (члены данных с одинаковым именем в базовом и производном классах) в классах контрактов данных обычно не рекомендуется, в случае с JSON его использование прямо запрещено.
Полиморфизм и типы IXmlSerializable
Типы IXmlSerializable можно полиморфно присваивать друг другу как обычно, при условии выполнения требований "известных типов" в соответствии с обычными правилами контракта данных. Однако сериализация типа IXmlSerializable вместо типа Object приводит к потере информации типа, поскольку результатом сериализации является строка JSON.
Полиморфизм и некоторые типы интерфейсов
Запрещается сериализовать тип коллекции или тип, реализующий интерфейс IXmlSerializable, там, где ожидается не являющийся коллекцией тип, который не сериализуется с использованием IXmlSerializable (за исключением Object). Например, вызывается IMyInterface
пользовательский интерфейс и тип, реализующий IEnumerable<T> как тип MyType
int
, так и IMyInterface
. Запрещено возвращать MyType
операцию с типом возвращаемого значения IMyInterface
. Это связано с тем, что MyType
необходимо сериализовать в виде массива JSON и требует указания типа, и как указано, прежде чем нельзя включить указание типа с массивами только с сложными типами.
Известные типы и конфигурация
Все механизмы "известных типов", используемые сериализатором DataContractSerializer, аналогичным образом поддерживаются сериализатором DataContractJsonSerializer. Оба сериализатора считывают один и тот же элемент конфигурации, dataContractSerializer> в <system.runtime.serialization>, чтобы обнаружить известные типы, добавленные через файл конфигурации.<
Коллекции, присвоенные объекту
Коллекции, присвоенные объекту, сериализуются так, как будто они реализуют интерфейс IEnumerable<T>: в виде массива JSON, где каждая запись имеет намек на тип, если это сложный тип. Например, типShape
, List<T> назначенный Object следующим образом.
[{"__type":"Shape:#MyApp.Shapes","x":50,"y":70},
{"__type":"Shape:#MyApp.Shapes","x":58,"y":73},
{"__type":"Shape:#MyApp.Shapes","x":41,"y":32}]
При десериализации обратно в Object:
Shape
должен находиться в списке известных типов. Наличие List<T> типаShape
в известных типах не влияет. Обратите внимание, что в этом случае не нужно добавлятьShape
известные типы при сериализации. Это выполняется автоматически.Коллекция десериализируется как Array тип Object , содержащий
Shape
экземпляры.
Производные коллекции, присвоенные базовым коллекциям
При присвоении производной коллекции базовой коллекции коллекция обычно сериализуется так, как если бы она была коллекцией базового типа. В то же время тип элемента производной коллекции нельзя присвоить типу элемента базовой коллекции: вызывается исключение.
Намеки на тип и словари
При присвоении словаря объекту Object каждая запись "ключ" и "значение" в словаре рассматривается так, как если бы она была присвоена объекту Object, и получает намек на тип.
При сериализации типов словарей на объект JSON, содержащий члены "Key" и "Value", не влияет значение параметра alwaysEmitTypeInformation
: он содержит намек на тип только там, где этого требуют рассмотренные выше правила сериализации коллекций.
Допустимые имена ключей JSON
Сериализатор кодирует в XML имена ключей, не являющиеся допустимыми XML-именами. Например, элемент данных с именем "123" будет иметь закодированное имя, например "_x0031__x0032__x0033_", так как "123" является недопустимым именем XML-элемента (начинается с цифры). Аналогичная ситуация может возникнуть с некоторыми международными кодировками, которые не допускаются в XML-именах. Описание этого эффекта XML для обработки JSON см. в разделе "Сопоставление между JSON и XML".