Conversor de XML para JSON
Converta XML para JSON ou JSON para XML, com atributos @, #text, arrays decididos pelo documento inteiro e a linha e a coluna onde o XML está mal formado.
A saída aparecerá aqui
O que esta ferramenta faz
O XML costuma chegar de sistemas que ninguém escolheu: uma resposta SOAP, um feed RSS, um arquivo de configuração, uma exportação de algo mais antigo que o JSON. O código que precisa usá-lo quer JSON. O contrário é igualmente comum: um payload JSON destinado a um sistema que só aceita XML. Esta página converte nas duas direções, no seu navegador, e lê os dois formatos com um único conjunto fixo de regras, para que as duas direções concordem sobre o que cada chave significa.
O que a diferencia é que a forma do JSON é decidida a partir do documento inteiro, e não do elemento que estiver sendo lido, e a página diz isso. Onde quer que essa decisão dê a um elemento uma forma diferente da que ele teria sozinho, um aviso abaixo da saída nomeia o caminho e a linha e a coluna em que ela se aplicou pela primeira vez. O que não tem lugar no JSON, como os comentários ou a ordem do conteúdo misto, é anunciado da mesma forma em vez de desaparecer, e na outra direção cada reescrita que o XML impõe ao seu JSON é nomeada no lugar em que aconteceu.
As regras: @ para um atributo, #text para o texto
Há um único conjunto de regras, e nenhuma configuração o altera. Um atributo vira uma chave escrita como @ seguido do nome do atributo, e o texto que precisa dividir o seu elemento com qualquer outra coisa vai sob a chave #text. Nem @ nem # podem começar um nome XML, então nenhuma chave escrita assim pode ser confundida com um elemento filho, e é isso que permite ler o mesmo JSON de volta como XML sem adivinhar. Aplicadas a um pequeno catálogo:
- O elemento raiz é a única chave no nível superior: um documento cujo elemento raiz é catalog vira um objeto com a única chave "catalog".
- Um elemento que não contém nada além de texto é esse texto: <title>Midnight Rain</title> vira "title": "Midnight Rain".
- Um atributo é uma chave ao lado dos elementos filhos: <book id="bk101"> dá ao livro "@id": "bk101", e cada elemento filho vem em seguida como uma chave, na ordem em que aparece pela primeira vez.
- Um elemento com atributos e texto guarda o texto sob #text: <price currency="USD">44.95</price> vira "price": {"@currency": "USD", "#text": 44.95}.
- Um elemento que se repete sob um mesmo pai vira um array: um livro cujo elemento author aparece duas vezes tem "author": ["Gambardella, Matthew", "Knorr, Stefan"].
- Os nomes são mantidos exatamente como estão escritos, prefixo incluído: <dc:title> vira a chave "dc:title", uma declaração de namespace vira uma chave de atributo como "@xmlns:dc", e nada é resolvido para um URI de namespace.
As entidades e as referências de caractere são decodificadas, então & chega como & e é como é, e uma seção CDATA é simplesmente texto. O espaço em branco sozinho entre elementos é formatação e é descartado; qualquer outro trecho de texto é mantido por inteiro e nunca é aparado. As duas normalizações que todo analisador de XML conforme aplica continuam vindo primeiro: um retorno de carro digitado no texto chega como quebra de linha, e uma tabulação ou uma quebra de linha digitadas em um valor de atributo chegam como espaço. Uma referência de caractere é a forma como um documento conserva um ou outro.
Por que o documento inteiro decide a forma
Um conversor que decide um elemento de cada vez escreve os autores do primeiro livro como um array, porque são dois, e o autor do segundo como uma string, porque é um só. Um elemento que traz um atributo é um objeto em um registro e texto simples no seguinte. O código escrito para o primeiro registro quebra no segundo, e nada ao longo do processo disse que a forma podia mudar.
Por isso a forma é decidida por caminho: os nomes dos elementos desde a raiz até um elemento, escritos /catalog/book/author, sem posições, de modo que todo autor de todo livro fique em um único caminho. Todos os elementos de um caminho são avaliados juntos:
- Arrays. Se o elemento se repete sob um mesmo pai, qualquer que seja ele, todo elemento do caminho é escrito como array, inclusive um que apareça sozinho.
- Objetos. Se algum elemento do caminho traz um atributo ou um elemento filho, todo elemento dele é escrito como objeto, inclusive um que só contém texto, e guarda o seu texto sob #text.
- Valores. Um caminho é lido como números só onde todos os seus valores se convertem, e como booleanos só onde todos os valores são true ou false, pela regra descrita mais abaixo, em números e booleanos.
- Elementos vazios. Um elemento vazio não participa dessas decisões, e assume o tipo de valor que o seu caminho estabelece.
Onde quer que o resultado seja diferente do que um elemento teria sido sozinho, a página diz isso uma vez para o caminho, com a linha e a coluna do primeiro elemento que isso mudou. Em um catálogo em que um livro tem vários autores e outro tem só um, esse único autor continua sendo um array; onde um preço traz um atributo currency e outro não, o preço simples continua sendo um objeto, com o texto sob #text. Os dois casos são anunciados, então nenhum deles surpreende o código que os lê.
Uma amostra com um só registro, e o campo «Sempre arrays»
A forma só pode ser tão boa quanto o documento a partir do qual é decidida. Cole um catálogo com um único livro e esse livro é um objeto, o seu único autor uma string e o seu preço um número, enquanto o mesmo catálogo com um segundo livro ao lado faz dos livros um array. Um caminho que aparece uma única vez em todo lugar do que você colou continua sendo um valor único, e um caminho cujos valores por acaso se convertem todos continua sendo de números até chegar um documento com um código postal que começa com zero. O JSON é exatamente tão confiável quanto a amostra é representativa, então cole mais de um registro sempre que puder.
Para os arrays existe uma solução que não depende da amostra. Digite em «Sempre arrays» os nomes de elemento ou os caminhos que precisam ser arrays, mostre o documento o que mostrar, separados por vírgulas ou espaços, e todo caminho a que um termo corresponde é escrito como array em todo lugar, mesmo onde aparece só uma vez:
- Um nome sozinho, como item, corresponde a todo caminho que termina em um elemento chamado item, esteja onde estiver.
- Um caminho como /rss/channel/item corresponde só a esse caminho, escrito do jeito que os caminhos abaixo da saída são escritos, então dá para copiar um de lá.
- A correspondência é exata: maiúsculas e minúsculas contam, e um prefixo faz parte do nome, então Item não corresponde a nenhum item e link não corresponde a nenhum atom:link.
- Cada caminho que o campo transformou em array é anunciado como qualquer outra decisão. Um termo que não é nem um nome nem um caminho, e um que não correspondeu a nenhum elemento do documento, aparecem listados abaixo do campo, e os termos que se aplicam continuam se aplicando.
O campo pertence à direção «XML para JSON». Ele guarda o que você digitou quando você troca de direção e volta, e, como toda configuração da página, não é mantido entre visitas. Os valores não têm um campo assim: desligar «Converter números e booleanos» serve para um caminho que precisa continuar sendo texto, contenha a amostra o que contiver, ao preço de todos os outros valores também virarem texto.
Números, booleanos, e por que 02134 continua sendo texto
No XML tudo é texto, e transformar em números JSON o texto que parece numérico costuma ser o que você quer. É também assim que um código postal 02134 vira 2134, e que um número de pedido longo perde os últimos dígitos. A regra aqui é a mesma que o conversor de CSV deste site usa, e não precisa de nenhuma lista de casos especiais: o texto vira número só onde esse número, escrito de volta, reproduz exatamente o texto. 42 reproduz, então é convertido. 02134 não reproduz, e o mesmo vale para 1.50, +5, 1e5 ou um inteiro longo demais para que um double guarde todos os seus dígitos. Os booleanos são exatamente true e false, em minúsculas.
O que esta página acrescenta é que a regra é aplicada a um caminho inteiro de uma vez. Um caminho é lido como números só se todos os seus valores se convertem, e como booleanos só se todos os valores são booleanos; um único valor que perderia um dígito, ou números e booleanos que se encontram em um mesmo caminho, deixam todos os valores ali como texto. Cada nome de atributo de um caminho é decidido separadamente. Um caminho mantido como texto embora alguns dos seus valores pudessem ser convertidos é anunciado, nomeando o caminho, e para um atributo o caminho termina no atributo, como em /catalog/book/@id.
«Converter números e booleanos» vem ligado quando a página abre, assim como o interruptor equivalente na página de CSV, e desligá-lo escreve todos os valores como texto. O valor de uma declaração de namespace nunca é lido como número, em nenhum dos dois casos, porque a norma Namespaces in XML define esse valor como um nome de namespace, que é texto.
Elementos vazios, e o null que o próprio documento indica
- Um elemento vazio assume o tipo de valor que o seu caminho estabelece. Em um caminho de texto, ele é a string vazia. Em um caminho de números ou de booleanos, é null, e a página diz isso, já que sozinho o elemento teria sido texto vazio.
- Vazio quer dizer absolutamente nada: <zip> </zip> contém um espaço, e um espaço é texto.
- Um caminho em que todos os elementos estão vazios é de texto, então cada um deles é a string vazia. Nada ali é lido como número, e um null seria uma informação que o documento nunca deu.
- Em um caminho escrito como objetos, um elemento vazio também traz #text, vazio ou null pela mesma regra, onde quer que outro elemento do caminho contenha texto: ao lado de <price currency="USD">5</price>, um <price/> vira {"#text": null}. Onde nenhum elemento do caminho contém texto, como no caso de elementos de imagem que só trazem um atributo src, nenhum deles traz #text.
Um documento também pode indicar null por conta própria. Um elemento marcado com xsi:nil="true", com esse prefixo vinculado ao namespace XML Schema instance, é null em qualquer caminho, esteja «Converter números e booleanos» como estiver. Essa indicação é a forma como o documento diz null em vez de dados, então nem o atributo nem uma declaração de namespace que não vincula mais nada aparecem no JSON. Qualquer prefixo vinculado a esse namespace funciona, e i:nil="1" diz a mesma coisa; xsi:nil="false" é um dado comum, e um elemento marcado como nil que ainda contém conteúdo fica como está, já que lê-lo como null descartaria esse conteúdo sem dizer nada.
O que não tem lugar no JSON, anunciado em vez de perdido
Parte do que um documento XML contém não tem lugar no JSON. O que tem significado é anunciado abaixo da saída em vez de ser descartado em silêncio:
- A ordem do conteúdo misto. Em <p>Hello <b>world</b>, again</p> o texto é reunido sob #text como "Hello , again" e o elemento b sob "b": todos os caracteres e todos os elementos sobrevivem, mas não a ordem em que estavam. Elementos filhos que alternam entre nomes perdem a ordem da mesma forma. Isso é anunciado uma vez para o caminho do elemento de cujo conteúdo se trata, e só onde a ordem se perdeu de fato, então <p><b>Note:</b> the rest</p> não gera nada, já que a ordem das suas chaves a preserva.
- Comentários e instruções de processamento. Ficam de fora, com um aviso para cada espécie que diz quantas ocorrências havia e onde está a primeira.
- O DOCTYPE. Também fica de fora, e o seu aviso diz que a DTD não foi aplicada: um valor padrão que a DTD declara para um atributo não aparece no JSON, porque esta ferramenta não lê a DTD.
- A declaração XML no topo. Fica de fora sem aviso, porque descreve como o texto está codificado, e não o que os dados são.
JSON de volta para XML: o XML mais próximo, e cada reescrita nomeada
Troque a direção e as mesmas regras funcionam ao contrário: uma chave @ vira um atributo, #text vira o texto do seu elemento, um array vira um elemento para cada membro, e qualquer outra chave vira um elemento filho, com os elementos filhos na ordem em que as suas chaves estão. Um null é escrito como um elemento vazio marcado com xsi:nil="true", com o namespace XML Schema instance declarado uma vez no elemento raiz e só quando um null é escrito, então converter de volta dá null outra vez em vez de uma string vazia. Tirando o JSON que não pode ser analisado, ou que está aninhado fundo demais para ser convertido, nada é recusado. Onde o seu JSON tem uma forma que o XML não consegue carregar como está, o XML bem formado mais próximo é escrito e a reescrita é nomeada abaixo da saída, em um JSONPath que você pode colar no Testador de JSONPath deste site:
- Qualquer coisa que não seja um único elemento raiz, sejam várias chaves no nível superior, nenhuma, um array no nível superior ou um valor solto, é escrita dentro de <root>.
- Uma chave que não é um nome XML é escrita com o nome mais próximo com que nenhuma outra chave ao lado dela é escrita: first name como first_name, e 1st como _1st.
- Um membro de um array que nenhuma chave nomeia, esteja ele dentro de outro array ou no nível superior, é escrito como um elemento <item>.
- Uma chave @ ou um #text que contém um objeto ou um array é escrito como elemento filho, já que nem um atributo nem um texto podem ter um.
- Uma chave @ que contém null fica de fora, e o mesmo acontece com um #text que contém null ao lado de elementos filhos, já que o XML só diz null de um elemento inteiro.
- Um caractere que o XML 1.0 não consegue conter de forma alguma, nem mesmo como referência, é substituído, e a página diz onde.
O escape faz parte de escrever XML bem formado, não é uma opção. Um < e um & sempre são escapados. Em um valor de atributo, uma aspa dupla também é, porque o valor é escrito entre duas delas; uma tabulação, uma quebra de linha ou um retorno de carro ali é escrito como referência de caractere, porque senão um analisador o transformaria em espaço. No texto, um retorno de carro é escrito como referência, porque senão um analisador o transformaria em quebra de linha, e ]]> nunca é escrito como está. É isso que permite ler o valor de volta como o valor que você escreveu.
O que a conversão de volta dá, dito antes de você converter
Há XML bem formado que ainda assim é lido de volta como algo diferente do JSON a partir do qual foi escrito, então a página lê o XML que acabou de escrever, pelas mesmas regras que a outra direção usa, e diz onde a resposta difere. Um array de um só membro é lido de volta como o seu único membro, a menos que os mesmos elementos se repitam sob um mesmo pai em outro lugar do documento. Um array vazio não escreve nenhum elemento e um #text vazio não escreve nenhum texto, então cada um deles é lido de volta como nada. Um objeto que não contém nada que seja escrito como atributo ou elemento filho é lido de volta como um valor simples, e onde os mesmos elementos em outro lugar fazem o documento decidir um array ou um objeto que o seu JSON não tinha, isso também é dito. Cada um desses casos é escrito como o seu JSON o tem, e anunciado.
«Usar como entrada» move a saída para o painel de entrada e troca a direção, então o que volta, e o que é anunciado, fica a um clique de distância. Onde nada é anunciado, o que volta é o seu JSON, tirando o que o XML não guarda. O texto XML não registra se um valor era um número, um booleano ou uma string: com «Converter números e booleanos» ligado, uma string que reproduz exatamente um número pode voltar como esse número, e com ele desligado todos os valores voltam como texto. E um atributo, ou um #text vazio ou null, pode voltar em outro lugar entre as chaves ao lado dele, porque o XML não guarda essa posição.
A ida e volta que parte do lado XML promete menos, de propósito. O texto que você colou não volta: a declaração, a formatação, os comentários e tudo o mais que foi anunciado na ida desaparecem. O que permanece estável é o XML que a página escreve: converta-o para JSON e de volta, com as mesmas configurações, e o mesmo XML volta.
Quando o XML ou o JSON não pode ser lido
Um documento que o analisador de XML não consegue ler é recusado com uma frase dizendo o que está errado, e uma linha e uma coluna sempre que houver um lugar a dar: um elemento que nunca é fechado, um valor de atributo sem aspas e um & que não começa nenhuma referência têm, cada um, uma frase própria. Uma tag de fechamento que não corresponde ao elemento ainda aberto diz isso e depois mostra a tag de fechamento de que esse elemento precisa, o que nomeia o elemento que ficou aberto. O JSON que não pode ser analisado é recusado da mesma forma, com a linha e a coluna em que o seu analisador parou sempre que isso puder ser medido.
Abaixo de uma frase que dá um lugar, a página mostra a sua própria linha com o caractere que falha realçado, o que importa mais em XML ou JSON minificado, em que o documento inteiro é uma única linha. Uma linha longa é reduzida ao trecho em torno do realce, com reticências onde foi cortada. Um caractere que falha e não desenha nada, como o fim do texto, uma tabulação ou uma marca de ordem de bytes, é realçado sobre um símbolo visível que ocupa o lugar dele. A coluna conta do jeito que o JavaScript conta uma string, em unidades de código UTF-16, então um emoji ou um ideograma raro antes do realce a desloca em dois em vez de em um.
Um documento aninhado mais fundo do que o site permite também é recusado, em qualquer das duas direções, e a sua frase informa o limite.
Perguntas frequentes
- Por que um único elemento é escrito como array?
- Porque um elemento do mesmo caminho se repete sob um mesmo pai em outro lugar do documento, e o caminho é decidido uma vez para o documento inteiro. O código que lê o valor como array passa então a funcionar para todo registro, inclusive os que têm um só elemento. A página nomeia o caminho, com a linha e a coluna do primeiro elemento que isso mudou. Para obter um array onde a sua amostra só tem um, escreva o nome do elemento em «Sempre arrays».
- Por que um número está entre aspas no meu JSON?
- Porque algum valor do mesmo caminho não sobreviveria como número, seja por um zero à esquerda, por um zero final depois do ponto decimal, por um sinal de mais ou por um expoente, seja porque números e booleanos se encontram nesse caminho. Um caminho assim é texto em todo lugar, e a página o nomeia. Os seus valores passam a ser convertidos assim que cada um deles for escrito do jeito que o número é escrito de volta, 2134 em vez de 02134.
- O que acontece com os comentários, as instruções de processamento e o DOCTYPE?
- Ficam de fora do JSON, e cada espécie é anunciada com quantas ocorrências havia e onde está a primeira. O aviso do DOCTYPE diz também que a DTD não foi aplicada, então qualquer valor padrão de atributo que ela declare está ausente.
- Ele verifica o meu XML contra uma DTD ou um XSD?
- Não. Ele lê XML bem formado e diz onde não conseguiu ler um documento, mas não valida contra uma DTD ou um XSD, e não aplica nada do que uma DTD declara. É por isso que um DOCTYPE é anunciado como não aplicado em vez de ser ignorado em silêncio.
- Como null é escrito em XML, e ele volta?
- Como um elemento vazio marcado com xsi:nil="true", com o namespace XML Schema instance declarado uma vez no elemento raiz. Converter esse XML de volta dá null outra vez, enquanto um elemento vazio simples teria voltado como uma string vazia em qualquer caminho lido como texto. Se o seu JSON já usa o prefixo xsi em um nome dele, a página declara um prefixo livre no lugar.
- O que acontece com uma chave que tem um espaço?
- Ela é escrita com o nome mais próximo que o XML permite, então first name vira first_name, e a página nomeia a chave pelo seu JSONPath junto com o nome em que ela se transformou. Cole esse JSONPath no Testador de JSONPath deste site para selecionar todos os valores a que a reescrita se aplicou.
- Por que converter de volta não me devolve o meu XML original?
- Porque o JSON não tem lugar para parte do que um arquivo XML contém: a declaração, a formatação entre os elementos, os comentários, as instruções de processamento, o DOCTYPE e a ordem do conteúdo misto. O que tinha significado foi anunciado na ida. O que permanece estável é o XML que a página escreve: leve-o para JSON e de volta, com as mesmas configurações, e o mesmo XML volta.
- Alguma coisa do que colo é enviada para um servidor?
- Não. As duas direções rodam inteiramente no seu navegador, por isso o documento que você cola, seja uma resposta de API, um feed ou um arquivo de configuração com credenciais dentro, nunca sai do seu dispositivo.
Ferramentas relacionadas
- Formatador JSON
Valida e embeleza JSON, com localizações de erro claras.
- Formatador SQL
Formata e embeleza SQL — vários dialetos.
- Formatador XML
Formata XML e verifica se está bem formado — embeleze ou minifique.
- Conversor de CSV para JSON
Converta CSV para JSON e de volta — com aspas tratadas corretamente.