2015-02-07 11 views
6

Ich bin in einer unmöglichen Situation stecken. Ich habe ein JSON aus dem Weltraum (es gibt keine Möglichkeit, es zu ändern). Hier ist die JSONDer effizienteste Weg, um einen ungültigen JSON zu beheben

{ 
    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" 
} 

"Es ist bei weitem nicht eine gültige JSON", sagte ich. Und ihre Antwort war "emmm aber Javascript kann es lesen, ohne beschweren!":

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

Problem

soll ich lesen und diese Zeichenfolge über .NET zu analysieren (4) und es brach 3 von 14 im C# -Abschnitt von Json.org erwähnten Bibliothek (habe den Rest von ihnen nicht versucht). Um das Problem zu beheben, schrieb ich folgende Funktion, um das Problem mit einfachen und doppelten Anführungszeichen zu beheben.

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 
} 

Jetzt JSONlint klagt nur über Attributnamen und ich kann beide JSON.NET und simplejson Bibliotheken über JSON parsen verwenden.

Frage

Ich bin sicher nicht der beste Weg, die oben genannten JSON der Festsetzung mein Code. Gibt es irgendein Szenario, dass mein Code brechen könnte? Gibt es einen besseren Weg, dies zu tun?

+0

Das JSON ist auf so vielen Ebenen so falsch. Aber wir können es reparieren. – Mouser

+0

Ich stimme dir vollkommen zu, aber da sie aus dem Weltraum kommen, sprechen sie nicht unsere Sprache und sie verstehen, dass es falsch ist, ist ... also unmöglich. – AaA

Antwort

6

Sie müssen dies über JavaScript ausführen. Starten Sie einen JavaScript-Parser in .net. Geben Sie die Zeichenfolge als Eingabe für JavaScript und verwenden JavaScript native JSON.stringify zu konvertieren:

\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)); 
 

Bitte beachten Sie, dass die Zeichenfolge (oder eher Objekt) Sie haben, ist nicht gültig JSON und kann‘ t mit einer JSON-Bibliothek analysiert werden. Es muss zuerst in gültiges JSON konvertiert werden. Es ist jedoch gültiges JavaScript.

Um diese Antwort zu vervollständigen: Sie können JavaScriptSerializer in .Net verwenden. Für diese Lösung benötigen Sie die folgenden Baugruppen:

  • 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

Große Antwort. Wenn Sie den ganzen Weg gehen wollen, fügen Sie ein Beispiel oder eine Liste von .Net JSON Parsern hinzu (vielleicht sogar einfach den einfachen WebBrowser?). Ordentlicher Trick mit den js Schnipsel in der Antwort, mir likey. – SimpleVar

+0

Es ist eine gute Idee, den Job jemandem zu geben, der weiß, wie man es macht, aber wie auch immer ich einen Javascript-Parser in .net laufen lasse? Behandelt 'Javascript.NET' oder' Jint' dieses Java-Objekt richtig? – AaA

+0

@BobSort, werfen Sie einen Blick auf die aktualisierte Antwort. Dies analysiert das schreckliche JSONish-Objekt und spuckt eine nette * .Net * Dictionary-Liste aus. Ich habe es mit deiner Quelle versucht und es hat funktioniert. – Mouser

2

Wie wäre es damit:

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

Oder einfach das Objekt nach Deserialize konsumieren, anstatt es zurück zu konvertieren t o String und weitergeben an einen JSON-Parser für zusätzliche Kopfschmerzen

Als Mouser auch erwähnt müssen Sie System.Web.Script.Serialization verwenden, die, indem system.web.extensions.dll in Ihrem Projekt zur Verfügung steht und das zu tun, was Sie brauchen Zielrahmen in Projekteigenschaften .NET Framework 4 zu ändern.

EDIT

Trick entserialisierten Objekt zu konsumieren ist dynamic

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

für JSON mit einfach in Ihrer Frage

string body = obj["body"]; 

oder wenn Ihr JSON verwenden ein Array

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

Wie kann ich das Objekt nach der Deserialisierung konsumieren? – AaA

+0

Haben Sie versucht, die JavaScript-Zeichenfolge in eine .Net-Zeichenfolge einzufügen? Es wird nicht funktionieren. Sie müssen es extern laden. Daher der Webclient. – Mouser