Изолированная сериализация JSON
JSON (JavaScript Object Notation, объектная нотация JavaScript) — формат данных, предназначенный специально для использования JavaScript-кодом, выполняемым на веб-страницах внутри браузера. Этот формат данных используется по умолчанию в службах ASP.NET AJAX, созданных в 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 | Примечания |
---|---|---|
Number |
Специальные значения, такие как Double.NaN, Double.PositiveInfinity и Double.NegativeInfinity, не поддерживаются и приводят к получению недопустимых JSON-данных. |
|
Number |
См. раздел «Перечисления и JSON» ниже. |
|
Boolean |
-- |
|
String |
-- |
|
String |
Формат этих типов в JSON идентичен формату в XML (а именно: TimeSpan имеет формат длительности, описанный в ISO 8601, GUID имеет формат «12345678-ABCD-ABCD-ABCD-1234567890AB», а URI представляется в форме исходной строки, например «http://www.example.com»). Точные сведения см. в разделе Справочник по схеме контрактов данных. |
|
String |
Формат — «имя:пространство_имен» (все до первого двоеточия является именем). Имя или пространство имен может отсутствовать. При отсутствии пространства имен можно также опустить двоеточие. |
|
Array of numbers |
Каждое число представляет значение одного байта. |
|
DateTime или String |
См. раздел «Даты-времена и JSON» ниже. |
|
Complex type |
См. раздел «Даты-времена и JSON» ниже. |
|
Типы XML и ADO.NET (XmlElement, DataSet). |
String |
См. раздел «Типы XML и JSON» ниже. |
Empty complex type |
-- |
|
Коллекции, словари и массивы |
Array |
См. раздел «Коллекции, словари и массивы» ниже. |
Сложные типы (с примененным атрибутом DataContractAttribute или SerializableAttribute) |
Complex type |
Члены данных становятся членами сложного типа Javascript. |
Сложные типы (реализующие интерфейс ISerializable) |
Complex type |
Сопоставляется аналогично другим сложным типам, однако некоторые типы 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. Словарь <string,object> может не поддерживаться так же, как в WCF, чего можно ожидать исходя из опыта работы с другими технологиями JSON. Например, если в словаре строка "abc" сопоставлена строке "xyz", а строка "def" строке 42, JSON-представление будет иметь вид не {"abc":"xyz","def":42}, а [{"Key":"abc","Value":"xyz"},{"Key":"def","Value":42}].
Если требуется работать непосредственно с JSON (обращаться к ключам и значениям динамически, без предварительного определения жесткого контракта), можно рассмотреть следующие варианты.
Использование примера Образец сериализации слабо типизированных данных JSON.
Использование интерфейса ISerializable и конструкторов десериализации — эти два механизма позволяют обращаться к парам "ключ-значение" JSON при сериализации и десериализации соответственно, однако не работают в сценариях с частичным доверием.
Работа с Сопоставление JSON и XML вместо использования сериализатора.
Под полиморфизмом в контексте сериализации понимается возможность сериализовать производный тип там, где ожидается его базовый тип. Существуют особые (только для JSON) правила, применяющиеся при полиморфном использовании коллекций, например при присвоении коллекции объекту Object. Этот вопрос более подробно рассмотрен в разделе "Дополнительные сведения для опытных пользователей" ниже.
Некоторые подробности
Порядок членов данных
Порядок членов данных при использовании JSON не имеет значения. В частности, даже если задан атрибут Order, JSON-данные все равно можно сериализовать в любом порядке.
Типы JSON
Тип JSON при десериализации не обязательно должен соответствовать приведенной выше таблице. Например, тип Int обычно сопоставляется числу JSON, однако может быть успешно десериализован из строки JSON, при условии, что строка содержит допустимое число. То есть, и {"q":42}, и {"q":"42"} допустимы, если имеется член данных типа Int с именем "q".
Полиморфизм
Полиморфная сериализация состоит в возможности сериализовать производный тип там, где ожидается его базовый тип. Эта возможность поддерживается для сериализации JSON в WCF аналогично тому, как поддерживается сериализация XML. Например, можно сериализовать тип MyDerivedType там, где ожидается тип MyBaseType, или сериализовать тип Int там, где ожидается тип 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), необходимо либо применить атрибут KnownTypeAttribute, к типу Animal, либо применить атрибут ServiceKnownTypeAttribute к операции и задать в этих атрибутах тип Cat. Дополнительные сведения см. в разделе Известные типы контрактов данных.
Подробное описание работы полиморфной сериализации и некоторых ограничений, которые необходимо принимать во внимание при ее использовании, см. в разделе "Дополнительные сведения для опытных пользователей" ниже.
Управление версиями
Функции управления версиями контрактов данных, включая интерфейс IExtensibleDataObject, полностью поддерживаются в JSON. Кроме того, в большинстве случаев можно десериализовать тип в один формат (например, XML) и затем сериализовать его в другой формат (например, JSON) и при этом сохранить данные в IExtensibleDataObject. Дополнительные сведения см. в разделе Контракты данных, совместимые с любыми будущими изменениями. Следует помнить, что JSON не придает значения порядку, поэтому любая информация о порядке будет потеряна. Кроме того, JSON не поддерживает множественные пары "ключ/значение" с одним и тем же именем ключа. Наконец, все операции над объектом IExtensibleDataObject по своей природе полиморфны — то есть, их производные типы присваиваются типу Object, базовому типу для всех типов.
JSON в URL-адресах
При использовании конечных точек ASP.NET AJAX с командой GET HTTP (с помощью атрибута WebGetAttribute), входящие параметры присутствуют в URL-адресе запроса, а не в теле сообщения. JSON поддерживается даже в URL-адресе запроса, поэтому в случае операции, принимающей тип Int с именем "number" и сложный тип 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. Например, если тип сериализует в своей реализации ISerializable тип enum, попытка десериализовать данные обратно в enum (без надлежащих приведений) завершится неудачей, поскольку тип enum сериализуется в JSON в виде чисел, а числа JSON десериализуются во встроенные числовые типы .NET (Int32, Decimal или Double). Поэтому тот факт, что число когда-то было значением перечисления (enum), теряется.
Тип с интерфейсом ISerializable, конструктор десериализации которого основан на определенном порядке десериализации, также может выдать ошибку при десериализации некоторых JSON-данных, поскольку большинство сериализаторов JSON не гарантируют никакого определенного порядка.
Типы производства
В то время как интерфейс IObjectReference в общем случае поддерживается в JSON, все типы, требующие возможности "типа производства" (возвращения методом GetRealObject экземпляра типа, отличного от типа, реализующего интерфейс), не поддерживаются.
Формат 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, они также преобразуются.
Преобразование происходит только при условии, что символы "/" предваряются escape-знаками (т. е. JSON-фрагмент выглядит так: "\/Date(700000+0500)\/"); по этой причине JSON-кодировщик WCF (реализуемый привязкой WebHttpBinding) всегда предваряет символ "/" escape-знаком.
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" (два символа подчеркивания и слово "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/) заменяется символом "#". (Чтобы эта замена была обратимой, используется escape-правило: если пространство имен начинается с символов "#" или "\", к ним добавляется дополнительный символ "\"). Таким образом, если "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"}
И сериализатор DataContractJsonSerializer, используемый в WCF, и клиентские страницы ASP.NET 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" — Shape.radius или Circle.radius). Следовательно, тогда как использовать принцип "сокрытия свойств" (члены данных с одинаковым именем в базовом и производном классах) в классах контрактов данных обычно не рекомендуется, в случае с JSON его использование прямо запрещено.
Полиморфизм и типы IXmlSerializable
Типы IXmlSerializable можно полиморфно присваивать друг другу как обычно, при условии выполнения требований "известных типов" в соответствии с обычными правилами контракта данных. Однако сериализация типа IXmlSerializable вместо типа Object приводит к потере информации типа, поскольку результатом сериализации является строка JSON.
Полиморфизм и некоторые типы интерфейсов
Запрещается сериализовать тип коллекции или тип, реализующий интерфейс IXmlSerializable, там, где ожидается не являющийся коллекцией тип, который не сериализуется с использованием IXmlSerializable (за исключением Object). Например, пользовательский интерфейс IMyInterface и тип MyType, реализующие и интерфейс IEnumerable типа int, и IMyInterface. Запрещается возвращать тип MyType из операции, тип возвращаемого значения которой — IMyInterface. Это связано с тем, что тип MyType должен сериализоваться как массив JSON и требует намека на тип, но, как говорилось выше, снабдить намеком на тип массив нельзя (намеками на тип снабжаются только сложные типы).
Известные типы и конфигурация
Все механизмы "известных типов", используемые сериализатором DataContractSerializer, аналогичным образом поддерживаются сериализатором DataContractJsonSerializer. Оба сериализатора считывают один и тот же элемент конфигурации — <dataContractSerializer> в <system.runtime.serialization> — для получения известных типов, добавленных посредством файла конфигурации.
Коллекции, присвоенные объекту
Коллекции, присвоенные объекту, сериализуются так, как будто они реализуют интерфейс IEnumerable: в виде массива JSON, где каждая запись имеет намек на тип, если это сложный тип. Например, коллекция List типа Shape, присвоенная объекту 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 типа 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.