¿Cómo convertir JSON a XML o XML a JSON?


282

Comencé a usar Json.NET para convertir una cadena en formato JSON a objeto o viceversa. No estoy seguro en el marco Json.NET, ¿es posible convertir una cadena en formato JSON a XML y viceversa?


Tenga en cuenta como dijo StaxMan, si hay ex. espacio en el nodo del elemento, será ignorado por xml. Por ej. "Identificación del alumno": 11000 no estará en el resultado xcuz de espacio en el nombre de la propiedad. xml no acepta tener espacio dentro del nodo del elemento.
Daniel B

Respuestas:


424

Si. Usando la clase JsonConvert que contiene métodos auxiliares para este propósito 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);

Documentación aquí: Conversión entre JSON y XML con Json.NET


3
No pude encontrar esta clase. Yo uso NewtonSoft Json.net 3.5.
David.Chu.ca

3
Parece que esta funcionalidad se ha movido a la clase Newtonsoft.Json.Converters.XmlNodeConverter en JSON.NET 3.5: james.newtonking.com/projects/json/help/html/…
David Brown

3
Solo para tu información, hay un problema potencial aquí. Cuando estaba convirtiendo una matriz de nodos xml en json, estaba haciendo una matriz en json. Pero, cuando ejecuto una matriz de nodos xml que tienen un recuento de 1, entonces la conversión json ya no formatea una matriz. Aquí se pierde una matriz xml con un solo elemento en la traducción.
Levitikon

3
Sorpresa sorpresa: esta es la impedancia entre XML y JSON, y la razón por la cual (IMO) no es una buena idea convertir directamente entre los dos. Pero, oye, hay muchos desarrolladores que están muy en desacuerdo aquí (según los votos negativos en mi respuesta) y no les importa estas conversiones de datos accidentales o la posible pérdida de datos ...
StaxMan

77
@StaxMan: Creo que todos pueden estar de acuerdo en que no hay una forma estandarizada de representar un documento XML en formato JSON. Su respuesta probablemente fue rechazada porque en realidad no respondió la pregunta. El OP no estaba preguntando si debería hacer la conversión, sino más bien si podría hacerlo utilizando las herramientas que ya están a su disposición.
David Brown

46

Sí, puede hacerlo (lo hago), pero tenga en cuenta algunas paradojas al convertir y maneje adecuadamente. No puede ajustarse automáticamente a todas las posibilidades de la interfaz, y hay un soporte integrado limitado para controlar la conversión; muchas estructuras y valores JSON no se pueden convertir automáticamente en ambos sentidos. Tenga en cuenta que estoy usando la configuración predeterminada con la biblioteca Newtonsoft JSON y la biblioteca MS XML, por lo que su kilometraje puede variar:

XML -> JSON

  1. Todos los datos se convierten en datos de cadena (por ejemplo, siempre obtendrá "falso" no falso o "0" no 0 ) Obviamente, JavaScript los trata de manera diferente en ciertos casos.
  2. Los elementos secundarios pueden convertirse en objetos anidados {} anidados O en matrices anidadas, [ {} {} ...]dependiendo de si solo hay uno o más de un elemento hijo XML. Consumiría estos dos de manera diferente en JavaScript, etc. Diferentes ejemplos de XML que se ajustan al mismo esquema pueden producir estructuras JSON realmente diferentes de esta manera. Puede agregar el atributo json: Array = 'true' a su elemento para solucionar esto en algunos (pero no necesariamente todos) los casos.
  3. Su XML debe estar bastante bien formado, he notado que no necesita ajustarse perfectamente al estándar W3C, pero 1. debe tener un elemento raíz y 2. no puede comenzar los nombres de los elementos con números son dos de los estándares XML forzados Lo he encontrado al usar las bibliotecas Newtonsoft y MS.
  4. En versiones anteriores, los elementos en blanco no se convierten a JSON. Son ignorados Un elemento en blanco no se convierte "elemento": nulo

Una nueva actualización cambia esto (Gracias a Jon Story por señalarlo): https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_NullValueHandling.htm

JSON -> XML

  1. Necesita un objeto de nivel superior que se convertirá en un elemento XML raíz o el analizador fallará.
  2. Los nombres de sus objetos no pueden comenzar con un número, ya que no pueden convertirse en elementos (XML es técnicamente aún más estricto que esto), pero puedo 'salirse' con romper algunas de las otras reglas de nomenclatura de elementos.

Por favor, siéntase libre de mencionar cualquier otro problema que haya notado, he desarrollado mis propias rutinas personalizadas para preparar y limpiar las cadenas a medida que convierto de un lado a otro. Su situación puede o no requerir preparación / limpieza. Como menciona StaxMan, su situación puede requerir que convierta entre objetos ... esto podría implicar interfaces apropiadas y un montón de declaraciones de casos / etc. para manejar las advertencias que menciono anteriormente.


¡Esta! Buena elaboración de en qué se basó mi respuesta corta (y muy rechazada en algún momento): hay muchas, muchas trampas si haces una conversión directa ciega. Puede que no estén bloqueando problemas para un uso específico, pero también pueden ser muy desagradables para otros.
StaxMan

1
Con respecto al n. ° 4 en XML -> JSON: puede usar la propiedad NullValueHandling para especificar que los valores nulos se deben incluir explícitamente - newtonsoft.com/json/help/html/…
Jon Story

La descripción del problema en este comentario se aplica bien a TODAS las implementaciones de algoritmos que convierten JSON a XML o al revés. Una vez que uno acepta que no es posible lograr simultáneamente una fidelidad bidireccional perfecta, y al mismo tiempo, entrada y salida de "parte" o "restricción" (esquema / formato dictado). - En el caso general.
DALDEI

33

Puede hacer estas conversiones también con .NET Framework:

JSON a XML: mediante System.Runtime.Serialization.Json

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

XML a JSON: utilizando 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 } };
}

Aparece un error en GetXmlData "El nombre 'GetXmlData' no existe en el contexto actual" ¿Hay una directiva de uso que me falta?
TimSmith-Aardwolf

44
@ TimSmith-Aardwolf, aquí está todo el código que necesita. Para usar System.Web.Script.Serialization necesita agregar el ensamblado System.Web.Extensions en Referencias.
Termininja

@Termininja, JSON a XML dándome tipo también, ¿cómo eliminar eso?
galleta

@Termininja, perfecto, gracias.
galleta

30

No estoy seguro de que haya un punto en dicha conversión (sí, muchos lo hacen, pero principalmente para forzar una clavija cuadrada a través del orificio redondo): hay un desajuste de impedancia estructural y la conversión es con pérdida. Por lo tanto, recomendaría contra tales transformaciones de formato a formato.

Pero si lo hace, primero convierta de json a objeto, luego de objeto a xml (y viceversa para la dirección inversa). Hacer una transformación directa conduce a resultados feos, pérdida de información o posiblemente ambos.


1
Aunque tu respuesta se rompió, me alegro de que esté aquí. Quiero hacer la conversión y estaba considerando omitir los objetos intermedios de c #, pero ahora no estoy tan seguro. De lo contrario, necesitaría generar objetos c # basados ​​en el XSD y dado que sería solo para fines de conversión, parecía una capa desperdiciada (y esfuerzo). Si tiene ejemplos o más detalles de cómo es con pérdida, sería genial verlo.
CRice el

No sé por qué esto fue rechazado. Actualmente estoy arreglando un montón de errores relacionados con varios pasos de transformación XML <-> JSON en un producto que tenemos. La mayoría se debe a la pérdida de tipos numéricos al convertir de JSON a XML.
rikkit

La dura verdad, respuesta útil.
FailedUnitTest

@CRice Años demasiado tarde, pero tener los objetos de transferencia conserva el esquema XML, hasta cierto punto. Por ejemplo, tal como lo menciona Levitikon , si intenta convertir un documento XML con una matriz de un solo elemento, el convertidor JSON no puede saber que es una matriz a menos que provenga de un objeto de transferencia con un tipo de matriz.
jpaugh

1
El XmlNodeConverter de Newtonsoft.JSON tiene una opción de configuración para evitar este problema al transferir de JSON a XML de nuevo a JSON, pero no puede detectar casos en los que el formato original es XML
jpaugh

27

Gracias por la respuesta de David Brown . En mi caso de JSON.Net 3.5, los métodos de conversión están bajo la clase 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);

44
Si sus datos son una matriz, entonces necesita hacer algo como esto: JsonConvert.DeserializeXmlNode ("{\" Row \ ":" + json + "}", "root"). ToXmlString () de lo contrario obtendrá un "XmlNodeConverter solo puede convertir JSON que comienza con un objeto ". excepción.
Mitchell Skurnik

Sí, y no puedes comenzar con un número. JsonConvert.DeserializeXmlNode ("{\" 1Row \ ":" + json + "}", "root"). ToXmlString () fallará
DaFi4

la respuesta anterior y el comentario de @mitchell me ayudan ... gracias
Ajay2707

8

Busqué durante mucho tiempo para encontrar un código alternativo a la solución aceptada con la esperanza de no usar un ensamblaje / proyecto externo. Se me ocurrió lo siguiente gracias al código fuente del proyecto 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: quería un XmlDocument en lugar de un XElement para fines de xPath. Además, este código obviamente solo va de JSON a XML, hay varias formas de hacer lo contrario.


1
Necesitaba hacer esto recientemente en un SQLCLR y no podía tomar una dependencia, así que solo mordí la viñeta y escribí esta rutina de conversión de json a xml , fue sorprendentemente simple y solo alrededor de 20 líneas de código.
gordy

¿Cómo eliminar Typr de XML?
galleta

6

Aquí está el código completo de c # para convertir xml a 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 convertir una cadena XML dada a JSON, simplemente llame a la función XmlToJSON () como se muestra a continuación.

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" }}

3

Prueba esta función. Lo acabo de escribir y no he tenido muchas oportunidades de probarlo, pero mis pruebas preliminares son prometedoras.

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;
}

2

Aquí hay un fragmento simple que convierte un XmlNode (recursivamente) en una tabla hash y agrupa varias instancias del mismo hijo en una matriz (como ArrayList). La tabla hash generalmente se acepta para convertir en JSON por la mayoría de las 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;
}

1

Cinchoo ETL : una biblioteca de código abierto disponible para realizar la conversión de Xml a JSON fácilmente con pocas líneas 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);
    }
}

Consulte el artículo de CodeProject para obtener ayuda adicional.

Descargo de responsabilidad: soy el autor de esta biblioteca.


0

Me gustó lo que dijo David Brown, pero obtuve la siguiente excepción.

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

Una solución sería modificar el archivo XML con un elemento raíz, pero eso no siempre es necesario y para una secuencia XML tampoco podría ser posible. Mi solución a continuación:

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);
            }
        }
    }
}

Ejemplo de XML que genera el error:

<parent>
    <child>
        Text
    </child>
</parent>
<parent>
    <child>
        <grandchild>
            Text
        </grandchild>
        <grandchild>
            Text
        </grandchild>
    </child>
    <child>
        Text
    </child>
</parent>

1
Su ejemplo XML no es un documento XML ya que no tiene un nodo raíz único. Sin embargo, eso podría ser un fragmento XML.
Robert McKee

0

He utilizado los siguientes métodos para convertir el JSON a 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();
  }
}

Y

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();
}

He usado la clase llamada Item para representar los 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....


0

Para convertir JSONcadena para XMLprobar esto:

    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 convertir XMLa JSONprobar esto:

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

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

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.