Como converter JSON para XML ou XML para JSON?

282

Comecei a usar o Json.NET para converter uma string no formato JSON em objeto ou vice-versa. Não tenho certeza no framework Json.NET, é possível converter uma string no formato JSON para XML e vice-versa?

David.Chu.ca
fonte
Observe como StaxMan disse, se houver ex. espaço no nó do elemento, ele será ignorado pelo xml. Por ex. "ID do aluno": 11000 não estará no resultado xml, por causa do espaço no nome da propriedade. O xml não aceita ter espaço no nó do elemento.
Daniel B

Respostas:

424

Sim. Usando a classe JsonConvert, que contém métodos auxiliares para este fim preciso:

// To convert an XML node contained in string xml into a JSON string   
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
string jsonText = JsonConvert.SerializeXmlNode(doc);

// To convert JSON text contained in string json into an XML node
XmlDocument doc = JsonConvert.DeserializeXmlNode(json);

Documentação aqui: Convertendo entre JSON e XML com Json.NET

David Brown
fonte
3
Não consegui encontrar esta turma. Eu uso o NewtonSoft Json.net 3.5.
David.Chu.ca
3
Parece essa funcionalidade foi movida para a classe Newtonsoft.Json.Converters.XmlNodeConverter em JSON.NET 3.5: james.newtonking.com/projects/json/help/html/...
David Brown
3
Apenas para sua informação, há um problema em potencial aqui. Quando eu estava transformando uma matriz de nós xml em json, ela estava criando uma matriz em json. Mas, quando executo uma matriz de nós xml com contagem de 1, a conversão json não formata mais uma matriz. Uma matriz xml com um único elemento é perdida na tradução aqui.
Levitikon 22/03/12
3
Surpresa surpresa - essa é a impedância entre XML e JSON e a razão pela qual (IMO) não é uma boa ideia converter diretamente entre os dois. Mas, hey, há muitas devs que Discordo aqui (como por downvotes sobre a minha resposta) e não se importam essas conversões de dados acidentais ou perda de dados potencial ...
StaxMan
7
@ StaxMan: Acho que todos podem concordar que não há uma maneira padronizada de representar um documento XML no formato JSON. Sua resposta provavelmente foi diminuída porque na verdade não respondeu à pergunta. O OP não estava perguntando se ele deveria fazer a conversão, mas se poderia fazê-lo usando as ferramentas que já estavam à sua disposição.
David Brown
46

Sim, você pode fazer isso (eu faço), mas esteja ciente de alguns paradoxos ao converter e manipule adequadamente. Você não pode estar em conformidade automaticamente com todas as possibilidades da interface e há um suporte interno limitado no controle da conversão - muitas estruturas e valores JSON não podem ser convertidos automaticamente nos dois sentidos. Lembre-se de que estou usando as configurações padrão das bibliotecas Newtonsoft JSON e MS XML, portanto, sua milhagem pode variar:

XML -> JSON

  1. Todos os dados se tornam dados de cadeia de caracteres (por exemplo, você sempre obtém "false", não false ou "0", não 0 ). Obviamente, o JavaScript os trata de maneira diferente em determinados casos.
  2. Os elementos filhos podem se tornar objeto {}aninhado OU matriz aninhada, [ {} {} ...]dependendo se houver apenas um ou mais de um elemento filho XML. Você consumiria esses dois de maneira diferente em JavaScript etc. Exemplos diferentes de XML em conformidade com o mesmo esquema podem produzir estruturas JSON realmente diferentes dessa maneira. Você pode adicionar o atributo json: Array = 'true' ao seu elemento para solucionar isso em alguns casos (mas não necessariamente em todos).
  3. Seu XML deve ser razoavelmente bem formado, notei que ele não precisa estar em conformidade com o padrão W3C, mas 1. você deve ter um elemento raiz e 2. não pode iniciar nomes de elementos com números são dois dos padrões XML impostos Eu descobri ao usar as bibliotecas Newtonsoft e MS.
  4. Nas versões anteriores, os elementos em branco não são convertidos para JSON. Eles são ignorados. Um elemento em branco não se torna "elemento": null

Uma nova atualização altera isso (Agradecemos a Jon Story por apontar): https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_NullValueHandling.htm

JSON -> XML

  1. Você precisa de um objeto de nível superior que será convertido em um elemento XML raiz ou o analisador falhará.
  2. Os nomes dos seus objetos não podem começar com um número, pois não podem ser convertidos em elementos (XML é tecnicamente ainda mais rigoroso que isso), mas eu posso 'fugir' com a quebra de algumas das outras regras de nomenclatura de elementos.

Por favor, sinta-se à vontade para mencionar outros problemas que tenha notado. Desenvolvi minhas próprias rotinas personalizadas para preparar e limpar as seqüências de caracteres à medida que eu me converto. Sua situação pode ou não exigir preparação / limpeza. Como o StaxMan menciona, sua situação pode realmente exigir a conversão entre objetos ... isso pode implicar interfaces apropriadas e várias instruções de caso / etc para lidar com as advertências mencionadas acima.

DaFi4
fonte
Este! Boa elaboração do que minha resposta curta (e que foi bastante prejudicada em algum momento) foi baseada - existem muitas armadilhas se você fizer uma conversão direta cega. Eles podem não estar bloqueando problemas para uso específico, mas também podem ser muito desagradáveis ​​para outros.
precisa saber é
1
Em relação a # 4 em XML -> JSON: você pode usar a propriedade NullValueHandling para especificar que valores nulos devem ser incluídos explicitamente - newtonsoft.com/json/help/html/…
Jon Story
A descrição do problema neste comentário se aplica bem a TODAS as implementações de algoritmos que convertem JSON em XML ou o inverso. Uma vez que se aceita que não é possível alcançar simultaneamente uma fidelidade bidirecional perfeita, e ao mesmo tempo éter "parte" ou "restrição" (esquema / formato pré-ditado), entrada e saída. - no caso geral.
DALDEI 27/04/19
33

Você pode fazer essas conversões também com o .NET Framework:

JSON para XML: usando System.Runtime.Serialization.Json

var xml = XDocument.Load(JsonReaderWriterFactory.CreateJsonReader(
    Encoding.ASCII.GetBytes(jsonString), new XmlDictionaryReaderQuotas()));

XML para JSON: usando System.Web.Script.Serialization

var json = new JavaScriptSerializer().Serialize(GetXmlData(XElement.Parse(xmlString)));

private static Dictionary<string, object> GetXmlData(XElement xml)
{
    var attr = xml.Attributes().ToDictionary(d => d.Name.LocalName, d => (object)d.Value);
    if (xml.HasElements) attr.Add("_value", xml.Elements().Select(e => GetXmlData(e)));
    else if (!xml.IsEmpty) attr.Add("_value", xml.Value);

    return new Dictionary<string, object> { { xml.Name.LocalName, attr } };
}
Termininja
fonte
Eu recebo um erro no GetXmlData "O nome 'GetXmlData' não existe no contexto atual" Existe uma diretiva de uso que está faltando?
TimSmith-Aardwolf
4
@ TimSmith-Aardwolf, Aqui está todo o código que você precisa. Para usar System.Web.Script.Serialization, é necessário adicionar o assembly System.Web.Extensions em References.
Termininja 21/07
@Termininja, JSON to XML, me dando o tipo também, como remover isso?
Cracker
@Termininja, Perfeito, Obrigado.
Cracker
30

Não tenho certeza de que haja sentido nessa conversão (sim, muitos fazem isso, mas principalmente para forçar um pino quadrado através do orifício redondo) - há incompatibilidade de impedância estrutural e a conversão é com perda. Então, eu recomendaria essas transformações de formato para formato.

Mas se você fizer isso, primeiro converta de json para objeto, depois de objeto para xml (e vice-versa para direção reversa). Fazer transformações diretas leva a resultados feios, perda de informações ou possivelmente a ambos.

StaxMan
fonte
1
Mesmo que sua resposta tenha sido esmagada, fico feliz que ela esteja aqui. Eu quero fazer a conversão e estava pensando em pular os objetos do meio c #, mas agora não tenho tanta certeza. Eu precisaria gerar objetos c # baseados no XSD de outra forma e, como seria apenas para fins de conversão, parecia uma camada desperdiçada (e esforço). Se você tiver exemplos ou mais detalhes de como é uma perda, seria ótimo ver isso.
CRice 01/08/19
Não sei por que isso foi prejudicado. Atualmente, estou corrigindo vários bugs relacionados a várias etapas de transformação XML <-> JSON em um produto que temos. A maioria está relacionada à perda de tipos numéricos ao converter de JSON para XML.
Rikkit
A dura verdade, resposta útil.
FailedUnitTest
@CRice Anos muito tarde, mas ter os objetos de transferência preserva o esquema XML, até certo ponto. Por exemplo, conforme apresentado pela Levitikon , se você tentar converter um documento XML com uma matriz de elemento único, a conversão JSON não poderá saber que é uma matriz, a menos que seja proveniente de um objeto de transferência com um tipo de matriz.
jpaugh
1
De Newtonsoft.JSON XmlNodeConverter tem uma opção de configuração para evitar esse problema quando da transferência de JSON para trás XML para JSON, mas não pode pegar casos em que o formato original é XML
jpaugh
27

Obrigado pela resposta de David Brown . No meu caso do JSON.Net 3.5, os métodos convert estão na classe estática JsonConvert:

XmlNode myXmlNode = JsonConvert.DeserializeXmlNode(myJsonString); // is node not note
// or .DeserilizeXmlNode(myJsonString, "root"); // if myJsonString does not have a root
string jsonString = JsonConvert.SerializeXmlNode(myXmlNode);
David.Chu.ca
fonte
4
Se seus dados forem uma matriz, será necessário fazer algo assim: JsonConvert.DeserializeXmlNode ("{\" Row \ ":" + json + "}", "root"). ToXmlString () caso contrário, você receberá um "XmlNodeConverter só pode converter JSON que começa com um objeto ". exceção.
Mitchell Skurnik
Sim, e você não pode começar com um número. JsonConvert.DeserializeXmlNode ("{\" 1Row \ ":" + json + "}", "root"). ToXmlString () falhará
DaFi4
a resposta acima e @mitchell comentário me ajuda .. obrigado
Ajay2707
8

Procurei por um longo tempo para encontrar código alternativo para a solução aceita, na esperança de não usar um assembly / projeto externo. Eu vim com o seguinte graças ao código fonte do projeto DynamicJson :

public XmlDocument JsonToXML(string json)
{
    XmlDocument doc = new XmlDocument();

    using (var reader = JsonReaderWriterFactory.CreateJsonReader(Encoding.UTF8.GetBytes(json), XmlDictionaryReaderQuotas.Max))
    {
        XElement xml = XElement.Load(reader);
        doc.LoadXml(xml.ToString());
    }

    return doc;
}

Nota: Eu queria um XmlDocument em vez de um XElement para fins de xPath. Além disso, esse código obviamente só vai de JSON para XML; existem várias maneiras de fazer o oposto.

yourbuddypal
fonte
1
Eu precisava fazer isso recentemente em um SQLCLR e não podia depender de uma dependência, então apenas mordi a bala e escrevi essa rotina de conversão de json para xml , era surpreendentemente simples e tinha apenas 20 linhas de código.
Gordy
Como remover typr de xml?
Cracker
6

Aqui está o código c # completo para converter xml para json

public static class JSon
{
public static string XmlToJSON(string xml)
{
    XmlDocument doc = new XmlDocument();
    doc.LoadXml(xml);

    return XmlToJSON(doc);
}
public static string XmlToJSON(XmlDocument xmlDoc)
{
    StringBuilder sbJSON = new StringBuilder();
    sbJSON.Append("{ ");
    XmlToJSONnode(sbJSON, xmlDoc.DocumentElement, true);
    sbJSON.Append("}");
    return sbJSON.ToString();
}

//  XmlToJSONnode:  Output an XmlElement, possibly as part of a higher array
private static void XmlToJSONnode(StringBuilder sbJSON, XmlElement node, bool showNodeName)
{
    if (showNodeName)
        sbJSON.Append("\"" + SafeJSON(node.Name) + "\": ");
    sbJSON.Append("{");
    // Build a sorted list of key-value pairs
    //  where   key is case-sensitive nodeName
    //          value is an ArrayList of string or XmlElement
    //  so that we know whether the nodeName is an array or not.
    SortedList<string, object> childNodeNames = new SortedList<string, object>();

    //  Add in all node attributes
    if (node.Attributes != null)
        foreach (XmlAttribute attr in node.Attributes)
            StoreChildNode(childNodeNames, attr.Name, attr.InnerText);

    //  Add in all nodes
    foreach (XmlNode cnode in node.ChildNodes)
    {
        if (cnode is XmlText)
            StoreChildNode(childNodeNames, "value", cnode.InnerText);
        else if (cnode is XmlElement)
            StoreChildNode(childNodeNames, cnode.Name, cnode);
    }

    // Now output all stored info
    foreach (string childname in childNodeNames.Keys)
    {
        List<object> alChild = (List<object>)childNodeNames[childname];
        if (alChild.Count == 1)
            OutputNode(childname, alChild[0], sbJSON, true);
        else
        {
            sbJSON.Append(" \"" + SafeJSON(childname) + "\": [ ");
            foreach (object Child in alChild)
                OutputNode(childname, Child, sbJSON, false);
            sbJSON.Remove(sbJSON.Length - 2, 2);
            sbJSON.Append(" ], ");
        }
    }
    sbJSON.Remove(sbJSON.Length - 2, 2);
    sbJSON.Append(" }");
}

//  StoreChildNode: Store data associated with each nodeName
//                  so that we know whether the nodeName is an array or not.
private static void StoreChildNode(SortedList<string, object> childNodeNames, string nodeName, object nodeValue)
{
    // Pre-process contraction of XmlElement-s
    if (nodeValue is XmlElement)
    {
        // Convert  <aa></aa> into "aa":null
        //          <aa>xx</aa> into "aa":"xx"
        XmlNode cnode = (XmlNode)nodeValue;
        if (cnode.Attributes.Count == 0)
        {
            XmlNodeList children = cnode.ChildNodes;
            if (children.Count == 0)
                nodeValue = null;
            else if (children.Count == 1 && (children[0] is XmlText))
                nodeValue = ((XmlText)(children[0])).InnerText;
        }
    }
    // Add nodeValue to ArrayList associated with each nodeName
    // If nodeName doesn't exist then add it
    List<object> ValuesAL;

    if (childNodeNames.ContainsKey(nodeName))
    {
        ValuesAL = (List<object>)childNodeNames[nodeName];
    }
    else
    {
        ValuesAL = new List<object>();
        childNodeNames[nodeName] = ValuesAL;
    }
    ValuesAL.Add(nodeValue);
}

private static void OutputNode(string childname, object alChild, StringBuilder sbJSON, bool showNodeName)
{
    if (alChild == null)
    {
        if (showNodeName)
            sbJSON.Append("\"" + SafeJSON(childname) + "\": ");
        sbJSON.Append("null");
    }
    else if (alChild is string)
    {
        if (showNodeName)
            sbJSON.Append("\"" + SafeJSON(childname) + "\": ");
        string sChild = (string)alChild;
        sChild = sChild.Trim();
        sbJSON.Append("\"" + SafeJSON(sChild) + "\"");
    }
    else
        XmlToJSONnode(sbJSON, (XmlElement)alChild, showNodeName);
    sbJSON.Append(", ");
}

// Make a string safe for JSON
private static string SafeJSON(string sIn)
{
    StringBuilder sbOut = new StringBuilder(sIn.Length);
    foreach (char ch in sIn)
    {
        if (Char.IsControl(ch) || ch == '\'')
        {
            int ich = (int)ch;
            sbOut.Append(@"\u" + ich.ToString("x4"));
            continue;
        }
        else if (ch == '\"' || ch == '\\' || ch == '/')
        {
            sbOut.Append('\\');
        }
        sbOut.Append(ch);
    }
    return sbOut.ToString();
 }
}

Para converter uma determinada string XML em JSON, basta chamar a função XmlToJSON () como abaixo.

string xml = "<menu id=\"file\" value=\"File\"> " +
              "<popup>" +
                "<menuitem value=\"New\" onclick=\"CreateNewDoc()\" />" +
                "<menuitem value=\"Open\" onclick=\"OpenDoc()\" />" +
                "<menuitem value=\"Close\" onclick=\"CloseDoc()\" />" +
              "</popup>" +
            "</menu>";

string json = JSON.XmlToJSON(xml);
// json = { "menu": {"id": "file", "popup": { "menuitem": [ {"onclick": "CreateNewDoc()", "value": "New" }, {"onclick": "OpenDoc()", "value": "Open" }, {"onclick": "CloseDoc()", "value": "Close" } ] }, "value": "File" }}
Nimesh khatri
fonte
3

Tente esta função. Acabei de escrever e não tive muita chance de testá-lo, mas meus testes preliminares são promissores.

public static XmlDocument JsonToXml(string json)
{
    XmlNode newNode = null;
    XmlNode appendToNode = null;
    XmlDocument returnXmlDoc = new XmlDocument();
    returnXmlDoc.LoadXml("<Document />");
    XmlNode rootNode = returnXmlDoc.SelectSingleNode("Document");
    appendToNode = rootNode;

    string[] arrElementData;
    string[] arrElements = json.Split('\r');
    foreach (string element in arrElements)
    {
        string processElement = element.Replace("\r", "").Replace("\n", "").Replace("\t", "").Trim();
        if ((processElement.IndexOf("}") > -1 || processElement.IndexOf("]") > -1) && appendToNode != rootNode)
        {
            appendToNode = appendToNode.ParentNode;
        }
        else if (processElement.IndexOf("[") > -1)
        {
            processElement = processElement.Replace(":", "").Replace("[", "").Replace("\"", "").Trim();
            newNode = returnXmlDoc.CreateElement(processElement);
            appendToNode.AppendChild(newNode);
            appendToNode = newNode;
        }
        else if (processElement.IndexOf("{") > -1 && processElement.IndexOf(":") > -1)
        {
            processElement = processElement.Replace(":", "").Replace("{", "").Replace("\"", "").Trim();
            newNode = returnXmlDoc.CreateElement(processElement);
            appendToNode.AppendChild(newNode);
            appendToNode = newNode;
        }
        else
        {
            if (processElement.IndexOf(":") > -1)
            {
                arrElementData = processElement.Replace(": \"", ":").Replace("\",", "").Replace("\"", "").Split(':');
                newNode = returnXmlDoc.CreateElement(arrElementData[0]);
                for (int i = 1; i < arrElementData.Length; i++)
                {
                    newNode.InnerText += arrElementData[i];
                }

                appendToNode.AppendChild(newNode);
            }
        }
    }

    return returnXmlDoc;
}
Jamon Crockom
fonte
2

Aqui está um trecho simples que converte um XmlNode (recursivamente) em uma hashtable e agrupa várias instâncias do mesmo filho em uma matriz (como um ArrayList). O Hashtable geralmente é aceito para converter em JSON pela maioria das bibliotecas JSON.

protected object convert(XmlNode root){
    Hashtable obj = new Hashtable();
    for(int i=0,n=root.ChildNodes.Count;i<n;i++){
        object result = null;
        XmlNode current = root.ChildNodes.Item(i);

        if(current.NodeType != XmlNodeType.Text)
            result = convert(current);
        else{
            int resultInt;
            double resultFloat;
            bool resultBoolean;
            if(Int32.TryParse(current.Value, out resultInt)) return resultInt;
            if(Double.TryParse(current.Value, out resultFloat)) return resultFloat;
            if(Boolean.TryParse(current.Value, out resultBoolean)) return resultBoolean;
            return current.Value;
        }

        if(obj[current.Name] == null)
            obj[current.Name] = result;
        else if(obj[current.Name].GetType().Equals(typeof(ArrayList)))
            ((ArrayList)obj[current.Name]).Add(result);
        else{
            ArrayList collision = new ArrayList();
            collision.Add(obj[current.Name]);
            collision.Add(result);
            obj[current.Name] = collision;
        }
    }

    return obj;
}
kronenthaler
fonte
1

Cinchoo ETL - uma biblioteca de código aberto disponível para fazer a conversão de XML para JSON facilmente com poucas linhas de código

Xml -> JSON:

using (var p = new ChoXmlReader("sample.xml"))
{
    using (var w = new ChoJSONWriter("sample.json"))
    {
        w.Write(p);
    }
}

JSON -> XML:

using (var p = new ChoJsonReader("sample.json"))
{
    using (var w = new ChoXmlWriter("sample.xml"))
    {
        w.Write(p);
    }
}

Artigo CheckPro CodeProject para obter ajuda adicional.

Disclaimer: Eu sou o autor desta biblioteca.

RajN
fonte
0

Eu fiz como David Brown disse, mas recebi a seguinte exceção.

$exception {"There are multiple root elements. Line , position ."} System.Xml.XmlException

Uma solução seria modificar o arquivo XML com um elemento raiz, mas isso nem sempre é necessário e, para um fluxo XML, também pode não ser possível. Minha solução abaixo:

var path = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, @"..\..\App_Data"));
var directoryInfo = new DirectoryInfo(path);
var fileInfos = directoryInfo.GetFiles("*.xml");

foreach (var fileInfo in fileInfos)
{
    XmlDocument doc = new XmlDocument();
    XmlReaderSettings settings = new XmlReaderSettings();
    settings.ConformanceLevel = ConformanceLevel.Fragment;

    using (XmlReader reader = XmlReader.Create(fileInfo.FullName, settings))
    {
        while (reader.Read())
        {
            if (reader.NodeType == XmlNodeType.Element)
            {
                var node = doc.ReadNode(reader);
                string json = JsonConvert.SerializeXmlNode(node);
            }
        }
    }
}

Exemplo de XML que gera o erro:

<parent>
    <child>
        Text
    </child>
</parent>
<parent>
    <child>
        <grandchild>
            Text
        </grandchild>
        <grandchild>
            Text
        </grandchild>
    </child>
    <child>
        Text
    </child>
</parent>
Ogglas
fonte
1
Seu exemplo XML não é um documento XML, pois não possui um nó raiz único. Isso poderia ser um fragmento XML no entanto.
Robert McKee
0

Eu usei os métodos abaixo para converter o JSON em XML

List <Item> items;
public void LoadJsonAndReadToXML() {
  using(StreamReader r = new StreamReader(@ "E:\Json\overiddenhotelranks.json")) {
    string json = r.ReadToEnd();
    items = JsonConvert.DeserializeObject <List<Item>> (json);
    ReadToXML();
  }
}

E

public void ReadToXML() {
  try {
    var xEle = new XElement("Items",
      from item in items select new XElement("Item",
        new XElement("mhid", item.mhid),
        new XElement("hotelName", item.hotelName),
        new XElement("destination", item.destination),
        new XElement("destinationID", item.destinationID),
        new XElement("rank", item.rank),
        new XElement("toDisplayOnFod", item.toDisplayOnFod),
        new XElement("comment", item.comment),
        new XElement("Destinationcode", item.Destinationcode),
        new XElement("LoadDate", item.LoadDate)
      ));

    xEle.Save("E:\\employees.xml");
    Console.WriteLine("Converted to XML");
  } catch (Exception ex) {
    Console.WriteLine(ex.Message);
  }
  Console.ReadLine();
}

Eu usei a classe chamada Item para representar os elementos

public class Item {
  public int mhid { get; set; }
  public string hotelName { get; set; }
  public string destination { get; set; }
  public int destinationID { get; set; }
  public int rank { get; set; }
  public int toDisplayOnFod { get; set; }
  public string comment { get; set; }
  public string Destinationcode { get; set; }
  public string LoadDate { get; set; }
}

Funciona....

Sai Ram Sagar
fonte
0

Para converter JSONstring para XMLtentar isso:

    public string JsonToXML(string json)
    {
        XDocument xmlDoc = new XDocument(new XDeclaration("1.0", "utf-8", ""));
        XElement root = new XElement("Root");
        root.Name = "Result";

        var dataTable = JsonConvert.DeserializeObject<DataTable>(json);
        root.Add(
                 from row in dataTable.AsEnumerable()
                 select new XElement("Record",
                                     from column in dataTable.Columns.Cast<DataColumn>()
                                     select new XElement(column.ColumnName, row[column])
                                    )
               );


        xmlDoc.Add(root);
        return xmlDoc.ToString();
    }

Para converter XMLpara JSONtentar isso:

    public string XmlToJson(string xml)
    {
       XmlDocument doc = new XmlDocument();
       doc.LoadXml(xml);

       string jsonText = JsonConvert.SerializeXmlNode(doc);
       return jsonText;
     }
Hasan Fathi
fonte