2015-02-07 17 views
6

Sono bloccato in una situazione impossibile. Ho un JSON dallo spazio esterno (non c'è modo che lo cambieranno). Ecco l'JSONIl modo più efficace per correggere un JSON non valido

{ 
    user:'180111', 
    title:'I\'m sure "E pluribus unum" means \'Out of Many, One.\' \n\nhttp://en.wikipedia.org/wiki/E_pluribus_unum.\n\n\'', 
    date:'2007/01/10 19:48:38', 
    "id":"3322121", 
    "previd":112211, 
    "body":"\'You\' can \"read\" more here [url=http:\/\/en.wikipedia.org\/?search=E_pluribus_unum]E pluribus unum[\/url]'s. Cheers \\*/ :\/", 
    "from":"112221", 
    "username":"mikethunder", 
    "creationdate":"2007\/01\/10 14:04:49" 
} 

"E non è neanche lontanamente un JSON valida", ho detto. E la loro risposta è stata "emmm ma Javascript può leggerlo senza lamentarsi!":

<html> 
<script type="text/javascript"> 
    var obj = {"PUT JSON FROM UP THERE HERE"}; 

    document.write(obj.title); 
    document.write("<br />"); 
    document.write(obj.creationdate + " " + obj.date); 
    document.write("<br />"); 
    document.write(obj.body); 
    document.write("<br />"); 
</script> 
<body> 
</body> 
</html> 

Problema

dovrei leggere e analizzare questa stringa tramite NET (4) e si è rotto 3 su 14 libreria menzionata nella sezione C# di Json.org (non ho provato il resto di loro). Per risolvere il problema, ho scritto la seguente funzione per risolvere il problema con virgolette singole e doppie.

public static string JSONBeautify(string InStr){ 
    bool inSingleQuote = false; 
    bool inDoubleQuote = false; 
    bool escaped = false; 

    StringBuilder sb = new StringBuilder(InStr); 
    sb = sb.Replace("`", "<°)))><"); // replace all instances of "grave accent" to "fish" so we can use that mark later. 
             // Hopefully there is no "fish" in our JSON 
    for (int i = 0; i < sb.Length; i++) { 
     switch (sb[i]) { 

      case '\\': 
       if (!escaped) 
        escaped = true; 
       else 
        escaped = false; 
       break; 
      case '\'': 
       if (!inSingleQuote && !inDoubleQuote) { 
        sb[i] = '"';   // Change opening single quote string markers to double qoute 
        inSingleQuote = true; 
       } else if (inSingleQuote && !escaped) { 
        sb[i] = '"';   // Change closing single quote string markers to double qoute 
        inSingleQuote = false; 
       } else if (escaped) { 
        escaped = false; 
       } 
       break; 
      case '"': 
       if (!inSingleQuote && !inDoubleQuote) { 
        inDoubleQuote = true; // This is a opening double quote string marker 
       } else if (inSingleQuote && !escaped) { 
        sb[i] = '`';   // Change unescaped double qoute to grave accent 
       } else if (inDoubleQuote && !escaped) { 
        inDoubleQuote = false; // This is a closing double quote string marker 
       } else if (escaped) { 
        escaped = false; 
       } 
       break; 
      default: 
       escaped = false; 
       break; 
     } 
    } 
    return sb.ToString() 
     .Replace("\\/", "/")  // Remove all instances of escaped/(\/) .hopefully no smileys in string 
     .Replace("`", "\\\"")  // Change all "grave accent"s to escaped double quote \" 
     .Replace("<°)))><", "`") // change all fishes back to "grave accent" 
     .Replace("\\'","'");  // change all escaped single quotes to just single quote 
} 

Ora JSONlint lamenta solo di nomi di attributi e posso utilizzare entrambe le librerie Json.NET e simplejson per analizzare sopra JSON.

Domanda

Sono sicuro che il mio codice non è il modo migliore di fissare menzionata JSON. C'è qualche possibilità che il mio codice si rompa? C'è un modo migliore per farlo?

+0

Questo JSON è così sbagliato su così tanti livelli. Tuttavia possiamo aggiustarlo. – Mouser

+0

Sono totalmente d'accordo con te, ma siccome provengono dallo spazio, non parlano la nostra lingua e facendoli capire che è sbagliato è ... beh impossibile. – AaA

risposta

6

È necessario eseguire ciò tramite JavaScript. Avvia un parser JavaScript in .net. Dare la stringa come input per Javascript e utilizzare nativo JSON.stringify per convertire di JavaScript:

\t obj = { 
 
\t \t "user":'180111', 
 
\t \t "title":'I\'m sure "E pluribus unum" means \'Out of Many, One.\' \n\nhttp://en.wikipedia.org/wiki/E_pluribus_unum.\n\n', 
 
\t \t "date":'2007/01/10 19:48:38', 
 
\t \t "id":"3322121", 
 
\t \t "previd":"112211", 
 
\t \t "body":"\'You\' can \"read\" more here [url=http:\/\/en.wikipedia.org\/?search=E_pluribus_unum]E pluribus unum[\/url]'s. Cheers \\*/ :\/", 
 
\t \t "from":"112221", 
 
\t \t "username":"mikethunder", 
 
\t \t "creationdate":"2007\/01\/10 14:04:49" 
 
\t } 
 

 
\t console.log(JSON.stringify(obj)); 
 
    document.write(JSON.stringify(obj)); 
 

Si ricorda che la stringa (o piuttosto oggetto) che hai non è valido JSON e puo' essere analizzato con una libreria JSON. Deve essere prima convertito in JSON valido. Tuttavia è un JavaScript valido.

Per completare questa risposta: È possibile utilizzare JavaScriptSerializer in .Net. Per questa soluzione avrete bisogno dei seguenti gruppi:

  • System.Net
  • System.Web.Script.Serialization

      var webClient = new WebClient(); 
          string readHtml = webClient.DownloadString("uri to your source (extraterrestrial)"); 
          var a = new JavaScriptSerializer(); 
    
          Dictionary<string, object> results = a.Deserialize<Dictionary<string, object>>(readHtml); 
    
+0

Ottima risposta. Se vuoi andare fino in fondo, includi un esempio o un elenco di parser di json .Net (forse anche solo usando il semplice WebBrowser?). Trucco pulito con i frammenti js nella risposta, mi piace. – SimpleVar

+0

È una buona idea dare il lavoro a qualcuno che sa come farlo, comunque qualche suggerimento su come eseguo un parser Javascript in .net? 'Javascript.NET' o' Jint' gestiscono correttamente questo oggetto java? – AaA

+0

@BobSort, dai un'occhiata alla risposta aggiornata. Questo analizzerà l'orribile oggetto JSONish e sputerà una bella lista di dizionari * .Net *. L'ho provato con la tua fonte e ha funzionato. – Mouser

2

ne dite di questo:

string AlienJSON = "your alien JSON"; 
JavaScriptSerializer js = new JavaScriptSerializer(); 
string ProperJSON = js.Serialize(js.DeserializeObject(AlienJSON)); 

O semplicemente consumare l'oggetto dopo la deserializzazione invece di convertirlo di nuovo t o corda e passarlo a un parser JSON per il mal di testa in più

Come Mouser menzionati anche è necessario utilizzare System.Web.Script.Serialization che è disponibile includendo system.web.extensions.dll nel progetto e per fare ciò è necessario modificare framework di destinazione nelle proprietà del progetto per .NET Framework 4.

EDIT

trucco per consumare oggetto deserializzato sta usando dynamic

JavaScriptSerializer js = new JavaScriptSerializer(); 
dynamic obj = js.DeserializeObject(AlienJSON); 

per JSON nella tua domanda è sufficiente utilizzare

string body = obj["body"]; 

o se il vostro JSON è un array

if (obj is Array) { 
    foreach(dynamic o in obj){ 
     string body = obj[0]["body"]; 
     // ... do something with it 
    } 
} 
+0

Come posso consumare l'oggetto dopo la deserializzazione? – AaA

+0

Hai provato a inserire la stringa JavaScript all'interno di una stringa .Net? Non funzionerà. Devi caricarlo esternamente. Da qui il webclient. – Mouser

Problemi correlati