Как конвертировать JSON в XML или XML в JSON? - PullRequest
260 голосов
/ 02 мая 2009

Я начал использовать Json.NET для преобразования строки в формате JSON в объект или наоборот. Я не уверен в структуре Json.NET, возможно ли преобразовать строку в формате JSON в формат XML и наоборот?

Ответы [ 13 ]

406 голосов
/ 02 мая 2009

Да. Используя класс JsonConvert, который содержит вспомогательные методы для этой конкретной цели:

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

Документация здесь: Преобразование между JSON и XML с помощью Json.NET

41 голосов
/ 13 августа 2012

Да, вы можете сделать это (я делаю), но помните о некоторых парадоксах при конвертации и обращайтесь с ними соответствующим образом. Вы не можете автоматически соответствовать всем возможностям интерфейса, и имеется ограниченная встроенная поддержка в управлении преобразованием - многие структуры и значения JSON не могут автоматически преобразовываться в обоих направлениях. Помните, что я использую настройки по умолчанию с библиотекой Newtonsoft JSON и библиотекой MS XML, поэтому ваш пробег может варьироваться:

XML -> JSON

  1. Все данные становятся строковыми данными (например, вы всегда получите "ложь" не ложь или "0" не 0 Очевидно, что в некоторых случаях JavaScript обрабатывает их по-разному.
  2. Дочерние элементы могут стать вложенным объектом {} ИЛИ вложенным массивом [ {} {} ...] в зависимости от наличия только одного или нескольких дочерних элементов XML. Вы бы по-разному использовали эти два в JavaScript и т. Д. Различные примеры XML, соответствующего одной и той же схеме, могут таким образом создавать действительно разные структуры JSON. Вы можете добавить атрибут json: Array = 'true' к своему элементу, чтобы обойти это в некоторых (но не обязательно во всех) случаях.
  3. Ваш XML должен быть достаточно правильно сформированным, я заметил, что нет необходимости полностью соответствовать стандарту W3C, но 1. у вас должен быть корневой элемент и 2. вы не можете запускать имена элементов с числами - два из обязательных стандартов XML, которые я обнаружил при использовании библиотек Newtonsoft и MS.
  4. В старых версиях пустые элементы не преобразуются в JSON. Они игнорируются. Пустой элемент не становится «элементом»: null

Новое обновление изменяет это (спасибо Jon Story за указание на это): https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_NullValueHandling.htm

JSON -> XML

  1. Вам необходим объект верхнего уровня, который преобразуется в корневой элемент XML, иначе анализатор не удастся.
  2. Ваши имена объектов не могут начинаться с цифры, поскольку они не могут быть преобразованы в элементы (XML технически даже более строг, чем этот), но я могу «сойти» с нарушением некоторых других правил именования элементов.

Пожалуйста, не стесняйтесь упоминать о любых других проблемах, которые вы заметили, я разработал свои собственные пользовательские процедуры для подготовки и очистки строк, когда я конвертирую туда-сюда. Ваша ситуация может требовать или не требовать подготовки / очистки. Как упоминает StaxMan, в вашей ситуации может потребоваться преобразование между объектами ... это может повлечь за собой соответствующие интерфейсы и кучу операторов case / etc для обработки предостережений, которые я упомянул выше.

32 голосов
/ 05 сентября 2015

Эти преобразования также можно выполнять с помощью .NET Framework:

JSON в XML: с использованием System.Runtime.Serialization.Json

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

XML в JSON: с использованием 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 } };
}
27 голосов
/ 03 мая 2009

Спасибо за ответ Дэвида Брауна. В моем случае JSON.Net 3.5 методы преобразования находятся в статическом классе 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);
27 голосов
/ 02 мая 2009

Я не уверен, что в таком преобразовании есть смысл (да, многие это делают, но в основном для проталкивания квадратного колышка через круглое отверстие) - несоответствие структурного импеданса и преобразование с потерями. Поэтому я бы рекомендовал против таких преобразований формата в формат.

Но если вы сделаете это, сначала преобразуйте из json в объект, затем из объекта в xml (и наоборот для обратного направления). Прямое преобразование приводит к ужасному выводу, потере информации или, возможно, к тому и другому.

8 голосов
/ 03 мая 2013

Я долго искал альтернативный код для принятого решения в надежде не использовать внешнюю сборку / проект. Благодаря исходному коду проекта 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;
}

Примечание: я хотел XmlDocument, а не XElement для целей xPath. Кроме того, этот код явно идет только из JSON в XML, есть разные способы сделать обратное.

6 голосов
/ 11 апреля 2016

Вот полный код C # для преобразования XML в 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();
 }
}

Чтобы преобразовать данную строку XML в JSON, просто вызовите функцию XmlToJSON (), как показано ниже.

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" }}
4 голосов
/ 03 марта 2011

Попробуйте эту функцию. Я только что написал это, и у меня не было шансов проверить это, но мои предварительные тесты обещают.

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 голосов
/ 06 июня 2014

Вот простой фрагмент, который преобразует XmlNode (рекурсивно) в хеш-таблицу и группирует несколько экземпляров одного и того же дочернего элемента в массив (как ArrayList). Hashtable обычно принимается для преобразования в JSON большинством библиотек 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;
}
0 голосов
/ 13 июня 2019

Для преобразования JSON строки в XML попробуйте это:

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

Для преобразования XML в JSON попробуйте это:

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

       string jsonText = JsonConvert.SerializeXmlNode(doc);
       return jsonText;
     }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...