Як конвертувати JSON в XML або XML в JSON?


282

Я почав використовувати Json.NET для перетворення рядка у формат JSON в об'єкт або навпаки. Я не впевнений в рамках Json.NET, чи можна перетворити рядок у JSON у формат XML і viceversa?


Зауважте, як сказав StaxMan, якщо є колишній. простір у вузлі елемента, він буде ігнорований xml. Для екс. "Студентський ідентифікатор": 11000 не буде в xml результати пробілу у назві властивості. xml не приймає місця в елементному вузлі.
Даніель Б

Відповіді:


424

Так. Використання класу 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


3
Я не змогла знайти цей клас. Я використовую NewtonSoft Json.net 3.5.
David.Chu.ca

3
Здається, ця функціональність була переміщена до класу Newtonsoft.Json.Converters.XmlNodeConverter в JSON.NET 3.5: james.newtonking.com/projects/json/help/html/…
Девід Браун

3
Просто FYI, тут є потенційна проблема. Коли я перетворював масив xml-вузлів до json, він робив масив у json. Але коли я пробігаю через масив xml-вузлів, які мають кількість 1, конверсія json більше не форматує масив. Тут перетворюється XML-масив з одним елементом.
Левитикон

3
Сюрприз-сюрприз - це імпеданс між XML та JSON, і причина, по якій (IMO) не є хорошою ідеєю безпосередньо конвертувати між ними. Але, ей, є багато чортів, які категорично не погоджуються тут (відповідно до моїх відповідей) і не проти цих випадкових перетворень даних або потенційної втрати даних ...
StaxMan

7
@StaxMan: Я думаю, кожен може погодитися, що немає стандартизованого способу подання XML-документа у форматі JSON. Ваша відповідь, ймовірно, була оскаржена, оскільки вона насправді не відповіла на запитання. ОП не запитував, чи слід робити конверсію, а скоріше, чи зможе це зробити за допомогою інструментів, які вже є у його розпорядженні.
Девід Браун

46

Так, ви можете це зробити (я це роблю), але пам'ятайте про деякі парадокси при перетворенні та керуйтеся належним чином. Ви не можете автоматично відповідати всім можливостям інтерфейсу, і існує обмежена вбудована підтримка в управлінні конверсією - багато структур JSON і значень не можуть автоматично перетворюватися обома способами. Майте на увазі, що я використовую налаштування за замовчуванням для бібліотеки Newtonsoft JSON та бібліотеки MS XML, тому ваш пробіг може відрізнятися:

XML -> JSON

  1. Усі дані стають рядковими даними (наприклад, ви завжди отримуватимете "false" не false або "0" not 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, ваша ситуація може насправді вимагати перетворення між об'єктами ... це може спричинити за собою відповідні інтерфейси та купу тверджень / тощо для обробки застережень, про які я згадував вище.


Це! Приємне роз'яснення того, на чому ґрунтувалася моя коротка (і сильно заперечена в якийсь момент) відповідь - є багато, багато підводних каменів, якщо робити сліпе пряме перетворення. Вони можуть не блокувати проблеми для конкретного використання, але також можуть бути дуже неприємними для інших.
StaxMan

1
Щодо №4 у XML -> JSON: ви можете використовувати властивість NullValueHandling, щоб вказати, що нульові значення повинні бути включені явно - newtonsoft.com/json/help/html/…
Jon Story

Опис проблеми в цьому коментарі добре стосується ВСІХ реалізацій алгоритмів, які перетворюють JSON в XML або в реверс. Як тільки можна визнати, що неможливо одночасно домогтися ідеальної двонаправленої вірності, і в той же час ефір "партії" або "обмеженої" (заздалегідь продиктованої схеми / формату) введення та виводу. - у загальному випадку.
DALDEI

33

Ці конверсії можна також виконати за допомогою .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 } };
}

Я отримую помилку на GetXmlData "Назва" GetXmlData "не існує в поточному контексті" Чи є у мене настанова про використання, яка мені не вистачає?
TimSmith-Aardwolf

4
@ TimSmith-Aardwolf, ось весь код, який вам потрібен. Для використання System.Web.Script.Serialization потрібно додати System.Web.Extensions збірку у Список літератури.
Термініня

@Termininja, JSON до XML, даючи мені також тип, як це видалити?
сухар

@Termininja, Ідеально, спасибі
сухар

30

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

Але якщо ви це зробите, спочатку перетворіть з json в об'єкт, потім з об'єкта в xml (і навпаки, у зворотному напрямку). Проведення прямої трансформації призводить до некрасивого результату, втрати інформації або, можливо, обох.


1
Незважаючи на те, що ваша відповідь була розбита, я радий, що вона тут. Я хочу зробити перетворення, і я розглядав можливість пропустити середні об'єкти c #, але зараз не так точно. Мені потрібно було б генерувати c # об’єкти на основі XSD в іншому випадку, і оскільки це було б виключно для цілей перетворення, це здавалося марним шаром (і зусиллям). Якщо у вас є приклади або більш детальна інформація про те, як це втрата, було б чудово побачити.
CRice

Не знаю, чому це було знято. Наразі я виправляю купу помилок, пов’язаних з декількома кроками перетворення XML <-> JSON у продукт, який у нас є. Більшість зводиться до втрати числових типів при перетворенні з JSON в XML.
rikkit

Важка правда, корисна відповідь.
FailedUnitTest

@CRice Роки занадто пізно, але наявність об'єктів передачі певною мірою зберігає схему XML. Наприклад, як підкреслив Levitikon , якщо ви намагаєтеся перетворити XML-документ із масивом одного елемента, перетворення JSON не може знати, що це масив, якщо він не надходить від об’єкта передачі з типом масиву.
jpaugh

1
XmlNodeConverter Newtonsoft.JSON має параметр конфігурації, щоб уникнути цієї проблеми при переході з JSON в XML назад до JSON, але він не може вловлювати випадки, коли оригінальний формат XML
jpaugh

27

Дякую за Девіда Брауна відповідь . У моєму випадку 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);

4
Якщо ваші дані є масивом, вам потрібно зробити щось подібне: JsonConvert.DeserializeXmlNode ("{\" Рядок \ ":" + json + "}", "root"). ToXmlString (), інакше ви отримаєте "XmlNodeConverter може конвертувати лише JSON, який починається з об’єкта. " виняток.
Мітчелл Скурник

Так, і ви не можете починати з числа. JsonConvert.DeserializeXmlNode ("{\" 1Row \ ":" + json + "}", "корінь"). ToXmlString () вийде з ладу
DaFi4

вищевказана відповідь та коментар @mitchell допоможіть мені .. дякую
Ajay2707

8

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


1
Мені потрібно було це зробити нещодавно в SQLCLR, і я не міг взяти на себе залежність, тому я просто покусав кулю і написав цю процедуру перетворення json-в-xml , це було напрочуд просто та було лише 20 рядків коду.
gordy

як видалити typr з xml?
сухар

6

Ось повний 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" }}

3

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

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

Ось простий фрагмент, який перетворює 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;
}

1

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 для отримання додаткової допомоги.

Відмова: Я автор цієї бібліотеки.


0

Мені було так, як сказав Девід Браун, але я отримав таке виняток.

$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>

1
Ваш приклад XML не є документом XML, оскільки він не має єдиного кореневого вузла. Однак це може бути фрагмент XML.
Роберт Маккі

0

Нижче я використовував методи перетворення 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; }
}

Це працює....


0

Щоб перетворити 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;
     }

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.