Partilhar via


Mapeando entre JSON e XML

Os leitores e gravadores produzidos pelo JsonReaderWriterFactory fornecem uma API XML sobre o conteúdo JSON (JavaScript Object Notation). JSON codifica dados usando um subconjunto dos literais de objeto de JavaScript. Os leitores e gravadores produzidos por essa fábrica também são usados quando o conteúdo JSON está sendo enviado ou recebido por aplicativos do Windows Communication Foundation (WCF) usando o WebMessageEncodingBindingElement ou o WebHttpBinding.

Quando inicializado com conteúdo JSON, o leitor JSON se comporta da mesma forma que um leitor XML textual faz sobre uma instância de XML. O gravador JSON, quando recebe uma sequência de chamadas que em um leitor XML textual produz uma determinada instância XML, grava o conteúdo JSON. O mapeamento entre esta instância de XML e o conteúdo JSON é descrito neste tópico para uso em cenários avançados.

Internamente, JSON é representado como um infoset XML quando processado pelo WCF. Normalmente, você não precisa se preocupar com essa representação interna, pois o mapeamento é apenas lógico: JSON normalmente não é fisicamente convertido em XML na memória ou convertido em JSON a partir de XML. O mapeamento significa que as APIs XML são usadas para acessar o conteúdo JSON.

Quando o WCF usa JSON, o cenário usual é que o DataContractJsonSerializer é automaticamente conectado pelo WebScriptEnablingBehavior comportamento ou pelo WebHttpBehavior comportamento quando apropriado. O DataContractJsonSerializer compreende o mapeamento entre JSON e o infoset XML e age como se estivesse lidando diretamente com JSON. (É possível usar o DataContractJsonSerializer com qualquer leitor ou gravador XML, com o entendimento de que o XML está em conformidade com o mapeamento a seguir.)

Em cenários avançados, pode ser necessário acessar diretamente o mapeamento a seguir. Esses cenários ocorrem quando você deseja serializar e desserializar JSON de maneiras personalizadas, sem depender do DataContractJsonSerializer, ou ao lidar com o Message tipo diretamente para mensagens que contêm JSON. O mapeamento JSON-XML também é usado para registro de mensagens. Ao usar o recurso de log de mensagens no WCF, as mensagens JSON são registradas como XML de acordo com o mapeamento descrito na próxima seção.

Para esclarecer o conceito de mapeamento, o exemplo a seguir é de um documento JSON.

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

Para ler este documento JSON usando um dos leitores mencionados anteriormente, use a mesma sequência de XmlDictionaryReader chamadas que você leria o seguinte documento XML.

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

Além disso, se a mensagem JSON no exemplo for recebida pelo WCF e registrada, você verá o fragmento XML no log anterior.

Mapeando entre JSON e o Infoset XML

Formalmente, o mapeamento é entre JSON conforme descrito no RFC 4627 (exceto com certas restrições relaxadas e certas outras restrições adicionadas) e o infoset XML (e não XML textual) conforme descrito em XML Information set. Consulte este tópico para obter as definições de itens de informação e campos em [colchetes].

Um documento JSON em branco mapeia para um documento XML em branco e um documento XML em branco mapeia para um documento JSON em branco. No mapeamento XML para JSON, não são permitidos espaços em branco anteriores e espaços em branco à direita após o documento.

O mapeamento é definido entre um Item de Informação do Documento (DII) ou um Item de Informação do Elemento (EII) e JSON. O EII, ou a propriedade [document element] do DII, é chamado de Elemento JSON Raiz. Observe que fragmentos de documento (XML com vários elementos raiz) não são suportados neste mapeamento.

Exemplo: O seguinte documento:

<?xml version="1.0"?>
<root type="number">42</root>

E o seguinte elemento:

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

Ambos têm um mapeamento para JSON. O <root> elemento é o elemento JSON raiz em ambos os casos.

Além disso, no caso de um DII, o seguinte deve ser considerado:

  • Alguns itens da lista [de crianças] não devem estar presentes. Não confie nesse fato ao ler XML mapeado a partir de JSON.

  • A lista [crianças] não contém itens de informação de comentários.

  • A lista [crianças] não contém itens de informação DTD.

  • A lista [crianças] não contém itens de informação pessoal (PI) (a <?xml…> declaração não é considerada um item de informação PI)

  • O conjunto [notações] está vazio.

  • O conjunto [entidades não analisadas] está vazio.

Exemplo: O documento a seguir não tem mapeamento para JSON porque [filhos] contém um IP e um comentário.

<?xml version="1.0"?>
<!--comment--><?pi?>
<root type="number">42</root>

O EII para o elemento JSON raiz tem as seguintes características:

  • [nome local] tem o valor "root".

  • [nome do namespace] não tem valor.

  • [prefixo] não tem valor.

  • [crianças] podem conter EIIs (que representam Elementos Internos, conforme descrito mais adiante) ou CIIs (Itens de Informação de Caracteres, conforme descrito mais adiante) ou nenhum destes, mas não ambos.

  • [atributos] podem conter os seguintes itens opcionais de informação de atributos (AIIs):

  • O JSON Type Attribute ("tipo"), conforme descrito mais adiante. Este atributo é usado para preservar o tipo JSON (string, number, boolean, object, array ou null) no XML mapeado.

  • O Atributo de Nome do Contrato de Dados ("__type"), conforme descrito mais adiante. Este atributo só pode estar presente se o atributo de tipo JSON também estiver presente e seu [valor normalizado] for "objeto". Este atributo é usado pelo para preservar informações de tipo de contrato de dados - por exemplo, em casos polimórficos DataContractJsonSerializer em que um tipo derivado é serializado e onde um tipo base é esperado. Se você não estiver trabalhando com o DataContractJsonSerializer, na maioria dos casos, esse atributo será ignorado.

  • [in-scope namespaces] contém a ligação de "xml" para http://www.w3.org/XML/1998/namespace conforme exigido pela especificação infoset.

  • [children], [attributes] e [in-scope namespaces] não devem ter nenhum item além do especificado anteriormente e [namespace attributes] não deve ter membros, mas não confie nesses fatos ao ler XML mapeado a partir de JSON.

Exemplo: O documento a seguir não tem mapeamento para JSON porque [atributos de namespace] não está vazio.

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

O AII para o atributo de tipo JSON tem as seguintes características:

  • [nome do namespace] não tem valor.
  • [prefixo] não tem valor.
  • [nome local] é "tipo".
  • [valor normalizado] é um dos valores de tipo possíveis descritos na seção a seguir.
  • [especificado] é true.
  • [tipo de atributo] não tem valor.
  • [referências] não tem valor.

O AII para o Atributo de Nome do Contrato de Dados tem as seguintes características:

  • [nome do namespace] não tem valor.
  • [prefixo] não tem valor.
  • [nome local] é "__type" (dois sublinhados e depois "tipo").
  • [normalized value] é qualquer string Unicode válida – o mapeamento dessa string para JSON é descrito na seção a seguir.
  • [especificado] é true.
  • [tipo de atributo] não tem valor.
  • [referências] não tem valor.

Os elementos internos contidos no elemento JSON raiz ou outros elementos internos têm as seguintes características:

  • [nome local] pode ter qualquer valor, conforme descrito mais adiante.
  • [namespace name], [prefix], [children], [attributes], [namespace attributes] e [in-scope namespaces] estão sujeitos às mesmas regras que o Elemento JSON Raiz.

Tanto no elemento JSON raiz quanto nos elementos internos, o atributo JSON Type define o mapeamento para JSON e os possíveis [filhos] e sua interpretação. O atributo [valor normalizado] diferencia maiúsculas de minúsculas e deve ser minúsculo e não pode conter espaço em branco.

[valor normalizado] do AII do JSON Type Attribute Permitido [filhos] do EII correspondente Mapeando para JSON
string (ou ausência do JSON tipo AII)

A string e a ausência do tipo JSON AII são os mesmos torna string o padrão.

Assim, <root> string1</root> mapeia para o JSON string "string1".
0 ou mais ICI A JSON string (JSON RFC, secção 2.5). Cada char um é um caractere que corresponde ao [código de caracteres] do CII. Se não houver CIIs, ele mapeia para um JSON stringvazio.

Exemplo: O seguinte elemento é mapeado para um fragmento JSON:

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

O fragmento JSON é "42".

No mapeamento XML para JSON, os caracteres que devem ser escapados mapeiam para caracteres com escape, todos os outros são mapeados para caracteres que não são escapados. O caractere "/" é especial – ele é escapado mesmo que não precise ser (escrito como "\/").

Exemplo: O elemento a seguir é mapeado para um fragmento JSON.

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

O fragmento JSON é "o \"da\/ta\"".

No mapeamento JSON para XML, todos os caracteres com escape e os caracteres que não são escapados mapeiam corretamente para o [código de caracteres] correspondente.

Exemplo: O fragmento JSON "\u0041BC", mapeia para o seguinte elemento XML.

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

A cadeia de caracteres pode ser cercada por espaço em branco ('ws' na seção 2 da RFC JSON) que não é mapeado para XML.

Exemplo: O fragmento JSON "ABC", (há espaços antes da primeira aspa dupla), mapeia para o seguinte elemento XML.

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

Qualquer espaço em branco em XML é mapeado para espaço em branco em JSON.

Exemplo: O seguinte elemento XML é mapeado para um fragmento JSON.

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

O fragmento JSON é " A BC ".
number 1 ou mais ICI A JSON number (JSON RFC, seção 2.4), possivelmente cercado por espaço em branco. Cada caractere na combinação número/espaço em branco é um caractere que corresponde ao [código de caracteres] do CII.

Exemplo: O elemento a seguir é mapeado para um fragmento JSON.

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

O fragmento JSON é 42

(O espaço em branco é preservado).
boolean 4 ou 5 CII (que corresponde a true ou false), possivelmente rodeados por ICI adicionais de espaço em branco. Uma sequência CII que corresponde à string "true" é mapeada para o literal true, e uma sequência CII que corresponde à string "false" é mapeada para o literal false. O espaço em branco circundante é preservado.

Exemplo: O elemento a seguir é mapeado para um fragmento JSON.

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

O fragmento JSON é false.
null Nenhum permitido. O literal null. No mapeamento JSON para XML, o pode ser cercado null por espaço em branco ('ws' na seção 2) que não é mapeado para XML.

Exemplo: O elemento a seguir é mapeado para um fragmento JSON.

<root type="null"/>

ou

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

:

O fragmento JSON em ambos os casos é Null.
object 0 ou mais EII. A begin-object (cinta curva esquerda) como na seção 2.2 do JSON RFC, seguido por um registro de membro para cada EII, conforme descrito mais adiante. Se houver mais de um EII, há separadores de valor (vírgulas) entre os registros de membros. Tudo isso é seguido por um objeto final (cinta direita).

Exemplo: O elemento a seguir é mapeado para o fragmento JSON.

<root type="object">

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

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

</root >

O fragmento JSON é {"type1":"aaa","type2":"bbb"}.

Se o Atributo de Tipo de Contrato de Dados estiver presente no mapeamento XML para JSON, um Registro de Membro adicional será inserido no início. Seu nome é o [nome local] do Atributo de Tipo de Contrato de Dados ("__type"), e seu valor é o [valor normalizado] do atributo. Por outro lado, no mapeamento JSON para XML, se o nome do primeiro registro de membro for o [nome local] do Atributo de Tipo de Contrato de Dados (ou seja, "__type"), um Atributo de Tipo de Contrato de Dados correspondente estará presente no XML mapeado, mas um EII correspondente não estará presente. Observe que esse registro de membro deve ocorrer primeiro no objeto JSON para que esse mapeamento especial seja aplicado. Isso representa um desvio do processamento JSON usual, onde a ordem dos registros de membros não é significativa.

Exemplo:

O fragmento JSON a seguir é mapeado para XML.

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

O XML é o código a seguir.

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

Observe que o __type AII está presente, mas não há __type EII.

No entanto, se a ordem no JSON for invertida, conforme mostrado no exemplo a seguir.

{"name":"John","\_\_type":"Person"}

O XML correspondente é mostrado.

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

Ou seja, __type deixa de ter significado especial e mapeia para um EII como de costume, não para um AII.

As regras de escape/unescapeping para o [valor normalizado] do AII quando mapeado para um valor JSON são as mesmas que para strings JSON, especificadas na linha "string" desta tabela.

Exemplo:

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

para o exemplo anterior pode ser mapeado para o seguinte JSON.

{"__type":"\\abc"}

Em um mapeamento XML para JSON, o primeiro EII [nome local] não deve ser "__type".

O espaço em branco (ws) nunca é gerado no mapeamento XML para JSON para objetos e é ignorado no mapeamento JSON para XML.

Exemplo: O fragmento JSON a seguir é mapeado para um elemento XML.

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

O elemento XML é mostrado no código a seguir.

<root type="object"> <ccc type="string">aaa</ccc> <ddd type="string">bbb</bar> </root >
matriz 0 ou mais EII Uma matriz inicial (colchete esquerdo) como na seção 2.3 da RFC JSON, seguida por um registro de matriz para cada EII, conforme descrito mais adiante. Se houver mais de um EII, há separadores de valor (vírgulas) entre os registros de matriz. Tudo isso é seguido por uma matriz final.

Exemplo: O seguinte elemento XML é mapeado para um fragmento JSON.

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

O fragmento JSON é ["aaa","bbb"]

O espaço em branco (ws) nunca é gerado no mapeamento XML para JSON para matrizes e é ignorado no mapeamento JSON para XML.

Exemplo: Um fragmento JSON.

["aaa", "bbb"]

O elemento XML para o qual ele é mapeado.

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

Os Registos de Membros funcionam da seguinte forma:

  • O elemento interno [nome local] mapeia para a string parte do member conforme definido na seção 2.2 do JSON RFC.

Exemplo: O elemento a seguir é mapeado para um fragmento JSON.

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

O fragmento JSON a seguir é exibido.

{"myLocalName":"aaa"}
  • No mapeamento XML para JSON, os caracteres que devem ser escapados em JSON são escapados e os outros não são escapados. O caractere "/", mesmo que não seja um caractere que deve ser escapado, é escapado no entanto (ele não precisa ser escapado no JSON para mapeamento XML). Isso é necessário para suportar o formato AJAX ASP.NET para DateTime dados em JSON.

  • No mapeamento JSON para XML, todos os caracteres (incluindo os caracteres não escapados, se necessário) são usados para formar um string que produz um [nome local].

  • Os elementos internos [crianças] são mapeados para o valor na seção 2.2, de acordo com o mesmo para o JSON Type AttributeRoot JSON Element. Vários níveis de aninhamento de EIIs (incluindo aninhamento em matrizes) são permitidos.

Exemplo: O elemento a seguir é mapeado para um fragmento 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 >

O fragmento JSON a seguir é o que ele mapeia.

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

Nota

Não há nenhuma etapa de codificação XML no mapeamento anterior. Portanto, o WCF suporta apenas documentos JSON onde todos os caracteres em nomes de chave são caracteres válidos em nomes de elementos XML. Por exemplo, o documento JSON {"<":"a"} não é suportado porque < não é um nome válido para um elemento XML.

A situação inversa (caracteres válidos em XML, mas não em JSON) não causa problemas porque o mapeamento anterior inclui etapas de fuga/desescape JSON.

Os registros de matriz funcionam da seguinte maneira:

  • O elemento interno [nome local] é "item".

  • Os [filhos] do elemento interno são mapeados para o valor na seção 2.3, de acordo com o Atributo de Tipo JSON, como acontece com o Elemento JSON Raiz. Vários níveis de aninhamento de EIIs (incluindo aninhamento dentro de objetos) são permitidos.

Exemplo: O elemento a seguir é mapeado para um fragmento 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>

A seguir está o fragmento JSON.

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

Consulte também