JSONをXMLまたはXMLからJSONに変換する方法


282

私は、Json.NETを使用してJSON形式の文字列をオブジェクトに、またはその逆に変換し始めました。Json.NETフレームワークではわかりませんが、JSONの文字列をXML形式に変換したり、その逆を行うことはできますか?


StaxManが言ったように、元がある場合は注意してください。要素ノードのスペースは、xmlによって無視されます。例のために。「学生ID」:11000は、プロパティ名のスペースのXML結果bcuzには含まれません。xmlはElement Node内にスペースを持つことを受け入れません。
ダニエルB

回答:


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.NETを使用したJSONとXML間の変換


3
このクラスは見つかりませんでした。NewtonSoft Json.net 3.5を使用しています。
David.Chu.ca、2009年

3
この機能はJSON.NET 3.5でNewtonsoft.Json.Converters.XmlNodeConverterクラスに移動された表示されます。james.newtonking.com/projects/json/help/html/...
デヴィッド・ブラウン

3
参考までに、ここには潜在的な問題があります。xmlノードの配列をjsonに変換していたとき、jsonで配列を作成していました。しかし、カウントが1のxmlノードの配列を実行すると、json変換で配列がフォーマットされなくなります。単一の要素を持つxml配列は、ここで翻訳中に失われます。
Levitikon、2012年

3
サプライズサプライズ-これはXMLとJSONの間のインピーダンスであり、2つを直接変換することが(IMO)にならない理由です。しかし、ちょっと、ここで(私の回答の反対投票に従って)強く反対し、これらの偶発的なデータ変換や潜在的なデータ損失を気にしない
多くの開発者がい

7
@StaxMan:XMLドキュメントをJSON形式で表現する標準化された方法がないことに誰もが同意できると思います。あなたの答えは、実際には質問に答えなかったため、おそらく反対票が投じられました。彼があればOPが求めていなかったはずです彼がいる場合ではなく、変換を行うことが、可能性が彼の処分で、既にツールを使用してそれを行います。
デビッドブラウン

46

はい、できます(私はできます)が、変換時にいくつかのパラドックスに注意し、適切に処理します。すべてのインターフェースの可能性に自動的に準拠することはできません。また、変換の制御には組み込みのサポートが制限されています。多くのJSON構造と値は、双方向で自動的に変換することはできません。私はNewtonsoft JSONライブラリとMS XMLライブラリでデフォルト設定を使用しているため、マイレージが異なる場合があることに注意してください。

XML-> JSON

  1. すべてのデータは、(たとえば、あなたが常に取得する文字列データとなる「偽」ではないまたは「0」ではない0明らかJavaScriptが特定のケースで異なるこれらを扱います)。
  2. 子要素は、XML子要素が1つだけあるか複数あるかによって、{}ネストされたオブジェクトまたはネストされた配列になり[ {} {} ...]ます。JavaScriptなどでこれら2つを異なる方法で使用します。同じスキーマに準拠するXMLの異なる例では、このように実際に異なるJSON構造を生成できます。要素に属性json:Array = 'true'を追加して、一部の(すべてではないが)場合にこれを回避することができます。
  3. XMLはかなり整形式である必要があります。W3C標準に完全に準拠する必要はないことに気付きましたが、1。ルート要素が必要です。2。要素名を数字で始めることはできません。 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 2016年

1
あなたはそのヌル値を指定するには、NullValueHandlingプロパティを使用することができ、明示的に含まれなければならない- :> JSON - XMLの#4についてnewtonsoft.com/json/help/html/...は
ジョンストーリー

この解説の問題の説明は、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'は現在のコンテキストに存在しません"欠落しているusingディレクティブはありますか?
TimSmith-Aardwolf 2016

4
@ TimSmith-Aardwolf、ここにあなたが必要とするすべてのコードがあります。用System.Web.Script.Serializationの使用して追加する必要System.Web.Extensionsを参考にアセンブリを。
Termininja

@ Termininja、JSONからXMLにタイプを指定して、それを削除する方法は?
クラッカー

@Termininja、パーフェクト、ありがとう。
クラッカー

30

そのような変換にポイントがあるかどうかはわかりません(そうです、多くはそうしますが、主に丸い穴に四角いペグを押し込むためです)-構造インピーダンスのミスマッチがあり、変換は損失を伴います。したがって、このような形式から形式への変換はお勧めしません。

ただし、その場合は、まずjsonからオブジェクトに変換し、次にオブジェクトからxmlに変換します(逆方向の場合はその逆)。直接変換を行うと、醜い出力、情報の損失、または場合によってはその両方が発生します。


1
あなたの答えが壊されたとしても、私はそれがここにあることを嬉しく思います。私は変換をしたいので、c#の中間オブジェクトをスキップすることを検討していましたが、今はよくわかりません。それ以外の場合は、XSDに基づいてc#オブジェクトを生成する必要があります。これは、純粋に変換の目的のみであるため、無駄なレイヤー(および労力)のように見えました。あなたがそれが非可逆である方法の例またはより詳細があるならば、それは見るのが素晴らしいでしょう。
CRice

これがなぜ反対票を投じたのかわからない。私は現在、製品のいくつかのXML <-> JSON変換ステップに関連する多数のバグを修正しています。ほとんどの場合、JSONからXMLに変換するときに数値型が失われます。
rikkit 2014年

難しい真実、有用な答え。
FailedUnitTest

@CRice年は遅すぎますが、転送オブジェクトがあると、XMLスキーマはある程度保持されます。たとえば、Levitikonによって提起されたように、単一の要素配列でXMLドキュメントを変換しようとした場合、JSON変換は、配列タイプの転送オブジェクトからのものでない限り、それが配列であることを認識できません。
jpaugh

1
Newtonsoft.JSONのXmlNodeConverterには、JSONからXMLに転送してJSONに戻すときにこの問題を回避するための構成オプションがありますが、元の形式がXMLであるケースをキャッチできません
jpaugh

27

David Brownの回答に感謝します。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( "{\" Row \ ":" + json + "}"、 "root")。ToXmlString()そうでない場合は、 "XmlNodeConverterオブジェクトで始まるJSONのみを変換できます。」例外。
Mitchell Skurnik、2015

はい。数字で始めることはできません。JsonConvert.DeserializeXmlNode( "{\" 1Row \ ":" + json + "}"、 "root")。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;
}

注:xPathの目的で、XElementではなくXmlDocumentが必要でした。また、このコードは明らかにJSONからXMLにのみ移行します。その逆を行う方法はさまざまです。


1
私は最近、SQLCLRでこれを行う必要があり、依存関係をとることができなかったので、弾丸をかじってこのjsonからxmlへの変換ルーチンを記述しました。これは驚くほど単純で、コードは約20行しかありませんでした。
gordy

typrをxmlから削除する方法?
クラッカー

6

xmlをjsonに変換する完全なc#コードは次のとおりです

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

1つの解決策は、ルート要素を使用して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;
     }

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.