Как конвертировать JSON в XML или XML в JSON?

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

12 ответов


да. Использование класса 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


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

XML - > В JSON

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

JSON - > XML

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

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


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

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

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

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


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

    }

это работает....