2016-06-06 4 views
0

Ich versuche, ein XML in Json mit Json.net (JsonConvert.SerializeXNode) zu konvertieren.Kann ich die Erstellung eines zusätzlichen "Objektknotens" während der Konvertierung eines XML-Arrays nach json mit json.net verhindern?

Es gibt ein Problem, wenn Sie versuchen, zwischen einem XML und einem JSON zu konvertieren, wenn Sie keine Art von Schema (xsd) verwenden, da Sie den Unterschied zwischen einer XML-Auflistung mit einem einzelnen Element nicht wirklich identifizieren können zu einem regulären Objekt.

Beispiel:

<Drivers> 
    <Driver> 
    <Name>MyName</Name> 
    </Driver> 
</Drivers> 

Wird in umgewandelt werden:

"Drivers":{ "Driver": { "Name": "MyName" } } 

da niemand den Serializer erzählt, dass die Fahrer sind eine Sammlung mit einem einzelnen Objekt und es denkt, es ist nur ein ganz normales Objekt.

Json.net hat eine Arbeit für diese mit der json:Array='true' Tagging.

Alles funktioniert gut, wenn Sie die Felder markieren, aber es schafft ein zusätzliches Mittel Objekt (Fahrer):

"Drivers": [{"Driver":{"Name": "MyName"}}] 

Jetzt verstehe ich, warum dieser Knoten erstellt wird, aber ich versuche, einen Weg zu finden umgehen Sie das Erstellen. Ich möchte dieses Resultat erhalten:

"Drivers": [{"Name": "MyName"}] 

Hat jemand irgendeine Idee, wie man etwas so macht?

+0

http://stackoverflow.com/questions/814001/ convert-json-zu-xml-oder-xml-zu-json –

+0

Amir, Sie haben es wahrscheinlich versucht, aber die Dokumente zu der Methode, die Sie erwähnen, zeigen einen Parameter namens 'omitRootObject' - hilft es hier? – Veverke

+0

@StephenBrickner - Ich habe das vor einer Weile gelesen und lese es noch einmal. Ich habe keine relevante Lösung in ihrem gefunden. Habe ich etwas übersehen? –

Antwort

1

Json.NET nicht automatisch eine Sammlung mit einem outer container element (beispielsweise eine generierte mit [XmlArray] angebracht) serialisiert konvertieren zu einem einzelnen JSON Array. Stattdessen müssen Sie die unerwünschte Verschachtelungsebene manuell reduzieren, indem Sie das XML mit LINQ-to-XML vorverarbeiten oder mit LINQ-to-JSON nachbearbeiten.

Da Sie bereits Ihr XML vorverarbeiten, um das json:Array='true'-Attribut hinzuzufügen, scheint das Hinzufügen einiger zusätzlicher Vorverarbeitungen am einfachsten zu sein. Erstens führen folgende Erweiterungsmethode:

public static class XNodeExtensions 
{ 
    /// <summary> 
    /// Flatten a two-level collection with an outer container element to a one-level collection 
    /// in preparation for conversion to JSON using Json.NET 
    /// </summary> 
    /// <param name="parents">The outer container elements.</param> 
    /// <param name="childName">The inner element name. If null, flatten all children.</param> 
    /// <param name="newChildName">The new element name. If null, use the parent name.</param> 
    public static void FlattenCollection(this IEnumerable<XElement> parents, XName childName = null, XName newChildName = null) 
    { 
     if (parents == null) 
      throw new ArgumentNullException(); 

     XNamespace json = @"http://james.newtonking.com/projects/json"; 
     XName isArray = json + "Array"; 

     foreach (var parent in parents.ToList()) 
     { 
      if (parent.Parent == null) 
       continue; // Removed or root 
      foreach (var child in (childName == null ? parent.Elements() : parent.Elements(childName)).ToList()) 
      { 
       child.Remove(); 
       child.Name = newChildName ?? parent.Name; 
       child.Add(new XAttribute(isArray, true)); 
       parent.Parent.Add(child); 
      } 
      if (!parent.HasElements) 
       parent.Remove(); 
     } 
    } 
} 

Sie können jetzt:

var xnode = XDocument.Parse(xml); 
xnode.Descendants("Drivers").FlattenCollection(); 
var json = JsonConvert.SerializeXNode(xnode, Formatting.Indented, true); 

und nutzen Sie die JSON Sie wollen. Probe fiddle.

Beachten Sie, dass <Drivers> nicht die root element dies tun kann, da ein XML-Dokument genau einen Stammknoten haben muss.

+1

Danke für Ihre Antwort. Ich dachte darüber nach, die XML als meinen letzten Plan zu verflachen und da ich keinen besseren Weg gefunden habe, es zu tun, werde ich es tun. Über die Implementierung habe ich das ein bisschen anders umgesetzt, um meinem Fall zu entsprechen. Danke für die Antwort. –

0

Wenn Sie das folgende Beispiel mit dem Flag omitRootObject ausführen, das auf "true" gesetzt ist, wird dies ausgeführt. Wenn Sie es auf false setzen, erhalten Sie tatsächlich den oberen Drivers-Knoten, den Sie loswerden wollen.

XmlDocument xmlDoc = new XmlDocument(); 
    xmlDoc.LoadXml(@"<Drivers> 
        <Driver> 
        <Name>MyName</Name> 
        </Driver> 
       </Drivers>"); 


    var result = JsonConvert.SerializeXmlNode(xmlDoc.FirstChild, Newtonsoft.Json.Formatting.Indented, true); 

    Console.WriteLine(result); 

Ausgang:

enter image description here

Set omitRootNode auf false, und Sie werden den Wurzelknoten Sie versuchen, erhalten, sie wieder loszuwerden.

enter image description here

+0

Zunächst ist Treiber nicht mein einziger Knoten. Ich habe ein großes XML und es ist ein Teil davon. Zweitens brauche ich die Antwort wie "Drivers": [{"Name": "MeinName"}] '. Danke für den Versuch. –

0

Ich habe die Abflachung ein bisschen anders implementiert. Ich habe Antwort DBC akzeptiert, da sie die Frage nicht beantworten, aber hier ist meine Implementierung nur für den Fall jemand in dem in Zukunft läuft und braucht es:

public static class XNodeExtensions 
{ 
    public static void FlattenCollection(this XElement parent) 
    { 
     if (parent == null || parent.Parent == null) 
      throw new ArgumentNullException(); 

     if (parent.Elements().Count() == 0) 
      return; 

     XNamespace json = @"http://james.newtonking.com/projects/json"; 
     XName isArray = json + "Array"; 

     foreach (var child in parent.Elements().ToList()) 
     { 
      child.Remove(); 
      child.Name = parent.Name; 
      child.Add(new XAttribute(isArray, true)); 
      parent.Parent.Add(child); 
     } 

     parent.Remove(); 
    } 
} 
Verwandte Themen