Вопрос

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

Это было полезно?

Решение

ДА.Используя класс 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

Другие советы

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

XML - > JSON

<Ол>
  • Все данные становятся строковыми данными (например, вы всегда получите " false " , а не false или " 0 " , а не 0 ) Очевидно, что в некоторых случаях JavaScript обрабатывает их по-разному.
  • Дочерние элементы могут стать вложенным объектом {} ИЛИ вложенным массивом [{} {} ...] , если существует только один или несколько XML. ребенок-элемент. Вы бы по-разному использовали эти два в JavaScript и т. Д. Различные примеры XML, соответствующего одной и той же схеме, могут таким образом создавать действительно разные структуры JSON. Вы можете добавить атрибут json: Array = 'true' к вашему элементу, чтобы обойти это в некоторых (но не обязательно во всех) случаях.
  • Ваш XML должен быть достаточно правильно сформированным, я заметил, что нет необходимости полностью соответствовать стандарту W3C, но 1. у вас должен быть корневой элемент и 2. вы не можете запустить элемент имена с номерами - это два из обязательных стандартов XML, которые я нашел при использовании библиотек Newtonsoft и MS.
  • В старых версиях пустые элементы не преобразуются в JSON. Они игнорируются. Пустой элемент не становится " элементом ": null
  • Новое обновление изменяет это (спасибо Джону Стори за указание на это): https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_NullValueHandling.htm

    JSON - > XML

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

    Эти преобразования также можно выполнять с помощью .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 } };
    }
    

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

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

    Спасибо за ответ Дэвида Брауна. В моем случае 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);
    

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

    Вот полный код 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" }}
    

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

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

    Вот простой фрагмент, который преобразует 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;
    }
    

    Я сделал, как сказал Дэвид Браун, но получил следующее исключение.

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

    Одним из решений было бы модифицировать файл XML с корневым элементом, но это не всегда необходимо, и для потока XML это также может оказаться невозможным. Мое решение ниже:

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

    Пример XML, который генерирует ошибку:

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

    Cinchoo ETL - библиотека с открытым исходным кодом, доступная для преобразования Xml в JSON легко с несколькими строками кода

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

    Закажите статью CodeProject для получения дополнительной справки.

    Отказ от ответственности: я являюсь автором этой библиотеки.

    Я использовал приведенные ниже методы для преобразования JSON в 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();
                }
            }
    

    и

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

    Я использовал класс с именем Item для представления элементов

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

    Это работает ....

    Для преобразования строки 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;
         }
    
    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top