La serializzazione Xml di JSON.Net fraintende gli array

Ho alcuni xmls generati automaticamente in cui alcune parti di xml possono avere più righe e altre no. Il risultato è che se c’è una riga viene restituito un nodo json singolo e se ho più righe viene restituito un array con nodes json.

Gli xml possono assomigliare a questo

   Testing 0      

O con più righe

    Update Documentation 0.5 2013-01-31 00:00:00 2013-01-01 00:00:00   Write jQuery example 0.05 2013-06-30 00:00:00 2013-01-02 00:00:00    

Quando si serializzano questi a JSON usando

 JsonConvert.SerializeXmlNode(xmldoc, Formatting.Indented); 

Il primo xml diventa questo

 { "List": { "Content": { "Row": { "@Index": "0", "Title": "Testing", "PercentComplete": "0", "DueDate": null, "StartDate": null } } } } 

E il secondo questo

 { "List": { "Content": { "Row": [{ "@Index": "0", "Title": "Update Documentation", "PercentComplete": "0.5", "DueDate": "2013-01-31 00:00:00", "StartDate": "2013-01-01 00:00:00" }, { "@Index": "1", "Title": "Write jQuery example", "PercentComplete": "0.05", "DueDate": "2013-06-30 00:00:00", "StartDate": "2013-01-02 00:00:00" }] } } } 

Come chiaramente si può vedere la riga sul secondo è un array come dovrebbe essere ma non sul primo. C’è qualche soluzione nota su questo tipo di problemi o ho bisogno di implementare il controllo nel mio frontend ricevendo il JSON (che sarebbe un po ‘problematico dal momento che le strutture sono molto dinamiche). Il modo migliore sarebbe se ci fosse un modo per forzare json.net a restituire sempre gli array.

Dalla documentazione di Json.NET: http://james.newtonking.com/projects/json/help/?topic=html/ConvertingJSONandXML.htm

È ansible forzare il rendering di un nodo come array aggiungendo l’attributo json:Array='true' al nodo XML che si sta convertendo in JSON. Inoltre, è necessario dichiarare lo spazio dei nomi del prefisso JSON nell’intestazione XML xmlns:json='http://james.newtonking.com/projects/json' oppure si otterrà un errore XML che indica che il prefisso JSON non è dichiarato.

Il prossimo esempio è fornito dalla documentazione:

 xml = @" Alan http://www.google.com Admin "; 

Uscita generata:

 { "person": { "@id": "1", "name": "Alan", "url": "http://www.google.com", "role": [ "Admin" ] } } 

Ho risolto questo comportamento in questo modo

 // Handle JsonConvert array bug var rows = doc.SelectNodes("//Row"); if(rows.Count == 1) { var contentNode = doc.SelectSingleNode("//List/Content"); contentNode.AppendChild(doc.CreateNode("element", "Row", "")); // Convert to JSON and replace the empty element we created but keep the array declaration returnJson = JsonConvert.SerializeXmlNode(doc).Replace(",null]", "]"); } else { // Convert to JSON returnJson = JsonConvert.SerializeXmlNode(doc); } 

È un po ‘sporco ma funziona. Sono ancora interessato ad altre soluzioni!

Dando il mio +1 a Iván Pérez Gómez e fornendo del codice qui per sostenere la sua risposta:

Aggiungere lo spazio dei nomi json.net richiesto al nodo radice:

 private static void AddJsonNetRootAttribute(XmlDocument xmlD) { XmlAttribute jsonNS = xmlD.CreateAttribute("xmlns", "json", "http://www.w3.org/2000/xmlns/"); jsonNS.Value = "http://james.newtonking.com/projects/json"; xmlD.DocumentElement.SetAttributeNode(jsonNS); } 

E per aggiungere json: attributo Array agli elementi trovati da xpath:

 private static void AddJsonArrayAttributesForXPath(string xpath, XmlDocument doc) { var elements = doc.SelectNodes(xpath); foreach (var element in elements) { var el = element as XmlElement; if (el != null) { var jsonArray = doc.CreateAttribute("json", "Array", "http://james.newtonking.com/projects/json"); jsonArray.Value = "true"; el.SetAttributeNode(jsonArray); } } } 

Ecco un esempio di un singolo nodo figlio come array json:

Ecco un esempio di un singolo nodo figlio come array json:

La mia soluzione: se JsonConvert non funziona, non usarlo. Analizza XML in dizionari / raccolte e poi in Json. Almeno in questo modo non è necessario codificare in modo rigido nessuno dei nomi degli elementi.

  private JsonResult AsJsonResult(XmlDocument result) { var kvp = new KeyValuePair(result.DocumentElement.Name, Value(result.DocumentElement)); return Json(kvp , JsonRequestBehavior.AllowGet); } ///  /// Deserializing straight from Xml produces Ugly Json, convert to Dictionaries first to strip out unwanted nesting ///  ///  ///  private object Value(XmlNode node) { dynamic value; //If we hit a complex element if (node.HasChildNodes && !(node.FirstChild is XmlText)) { //If we hit a collection, it will have children which are also not just text! if (node.FirstChild.HasChildNodes && !(node.FirstChild.FirstChild is XmlText)) { //want to return a list of Dictionarys for the children's nodes //Eat one level of the hierachy and return child nodes as an array value = new List(); foreach (XmlNode childNode in node.ChildNodes) { value.Add(Value(childNode)); } } else //regular complex element return childNodes as a dictionary { value = new Dictionary(); foreach (XmlNode childNode in node.ChildNodes) { value.Add(childNode.Name, Value(childNode)); } } } else //Simple element { value = node.FirstChild.InnerText; } return value; } 

Trovato lo stesso problema con XDocument

if (XDocument.Parse (“5.0021.0045.00”). Discendenti (“riga”). Count ()> 1) {}

  if (XDocument.Parse("1.005.0045.006.0010.0065.0011.00100.0098.00").Descendants("row").Count() > 1) { }