Is there a better way to "Pretty Print" the json string than I'm using
Asked Answered
I

7

32

I have json data comes server side.

In case I use the next code I get not pretty printed one line string:

print(String(bytes: jsonData, encoding: String.Encoding.utf8))

To make it pretty printed I use the next code:

if let json = try? JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers) {
   if let prettyPrintedData = try? JSONSerialization.data(withJSONObject: json, options: .prettyPrinted) {
      print(String(bytes: prettyPrintedData, encoding: String.Encoding.utf8) ?? "NIL")
   }
}

But seems that it isn't the best way.

So does anybody know how to pretty print incoming jsonData to print it?

Illfounded answered 30/4, 2018 at 22:47 Comment(12)
"But seems that it isn't the best way." what's wrong with it, exactly?Bambara
@Alexander, Wrong that this code converts jsonData to jsonObject than converts jsonObject to jsonData. It is like a work which needs to be done twice.Illfounded
Where does jsonData come from originally? At the place you need it pretty printed, do you have the source object it was generated from?Bambara
@Alexander, I use Alamofire to send a request. The response contains json data. So I would like to print it right after the app received the responseIllfounded
Pretty printing requires placing white space in all the right places. Determining what all the right places are is pretty much the same as deserializing JSON, the only difference being that you don't need to interpret the parsed fields to build an object graph. But that doesn't take too much time, so it would be silly to write a separate JSON parser that parses the string solely for the purpose of pretty printingBambara
FYI - the use of .mutableContainers is pointless in Swift and really pointless just for the sake of pretty printing.Christian
@Alexander, thanks for clarifying.Illfounded
@rmaddy, which reading option you suggest to use?Illfounded
Since you need to remove the only specified option, you would specify no options. ..., options: []). And since that is the default, simply leave off the options: parameter.Christian
@rmaddy, thanks. It is really logical)Illfounded
@Illfounded I would try to make use of an already-deserailized data, and reserialize it to JSON with the pretty printing option enabled, if you really need JSON. Otherwise, I think it's better to just dump the deserialized object. Also, I'd recommend using Codable instead of JSONSerializationBambara
@Alexander, I prefer using Codable but I'm working on the project written few years ago, so it can takes some time to rewrite deserialization logicIllfounded
S
48

A slightly prettier version of what you have:

if let json = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers),
   let jsonData = try? JSONSerialization.data(withJSONObject: json, options: .prettyPrinted) {
    print(String(decoding: jsonData, as: UTF8.self))
} else {
    print("json data malformed")
}
Showpiece answered 9/2, 2019 at 2:49 Comment(0)
B
15

Use the output formatting option on the encoder directly:

let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
Brooch answered 10/7, 2020 at 11:0 Comment(2)
This only works if your side is doing the encoding. From his other comments, he's getting something from the server so he doesn't have that option.Crag
Although this might answer another question, this solved exactly what I googled for.Desultory
F
11

Basically in Swift exists 2 types for strings: String and NSString

The second one is older (used even in Objective-C) and nowadays more often is used newer String type. However, NSString allows you to pretty print existing strings, which means that f.ex. backslashes will be deleted automatically.

Json received as Data from server

For this case I use such helper:

extension Data {
    var prettyString: NSString? {
        return NSString(data: self, encoding: String.Encoding.utf8.rawValue) ?? nil
    }
}

It's very important to use NSString over String type.

Alternatively you can operate on String, but in the end cast it to AnyObject, like below:

String(data: stringData, encoding: .utf8)! as AnyObject

The result in console looks like this (example of server response):

{
  "message" : "User could not log in",
  "errorCode" : "USER_COULD_NOT_LOG_IN",
  "parameters" : null
}

Pretty string for existing string

To prettify any string you can use second method from above, so cast String to AnyObject. It will also make string looking better. F.ex.:

let myStr: String = ...
print(myStr as AnyObject)
Fling answered 12/8, 2021 at 15:46 Comment(0)
U
7

Swift 5 and above

handy extension on Data to pretty-print JSON

extension Data {
    
    func printJson() {
        do {
            let json = try JSONSerialization.jsonObject(with: self, options: [])
            let data = try JSONSerialization.data(withJSONObject: json, options: .prettyPrinted)
            guard let jsonString = String(data: data, encoding: .utf8) else {
                print("Inavlid data")
                return
            }
            print(jsonString)
        } catch {
            print("Error: \(error.localizedDescription)")
        }
    }
}

How to Use:

 let json = """
  {
    "id": 1,
    "name": "Steve Jobs",
    "username": "Steve",
    "email": "[email protected]",
    "address": {
      "street": "Kulas Light",
      "suite": "Apt. 556",
      "city": "San Jose",
      "zipcode": "1234-5678"
    },
    "phone": "1-770-736-8031 x56442"
  }
"""

let jsonData = Data(json.utf8)
// log json data in pretty format
jsonData.printJson()
Uxorious answered 25/4, 2022 at 13:12 Comment(0)
I
3

Data extension:

extension Data {
    
    func printFormatedJSON() {
        if let json = try? JSONSerialization.jsonObject(with: self, options: .mutableContainers),
           let jsonData = try? JSONSerialization.data(withJSONObject: json, options: .prettyPrinted) {
            pringJSONData(jsonData)
        } else {
            assertionFailure("Malformed JSON")
        }
    }
    
    func printJSON() {
        pringJSONData(self)
    }
    
    private func pringJSONData(_ data: Data) {
        print(String(decoding: data, as: UTF8.self))
    }
}

Usage:

data.printFormatedJSON()
Illona answered 29/11, 2021 at 13:13 Comment(0)
E
0

here's the answer.

language: Objective-C


NSString+PrettyPrint.h

@interface NSString (PrettyPrint)

+ (NSString * _Nonnull)prettifiedJsonStringFromData:(nullable NSData *)data;
+ (NSString * _Nonnull)prettifiedStringFromDictionary:(nullable NSDictionary *)dictionary;

@end

NSString+PrettyPrint.m

#import "NSString+PrettyPrint.h"

@implementation NSString (PrettyPrint)

+ (NSString *)prettifiedStringFromDictionary:(nullable NSDictionary *)dictionary {
    
    if (dictionary == nil) { return @"nil"; }
    
    NSMutableString *returnStr = [NSMutableString stringWithString:@"[ \n"];
    
    for (NSString *key in dictionary) {
        [returnStr appendFormat:@"  %@: %@,\n", key, [dictionary valueForKey:key]];
    }

    [returnStr appendFormat:@"]"];

    return returnStr;
}

+ (NSString *)prettifiedJsonStringFromData:(nullable NSData *)data {
    
    if (data == nil) { return @"nil"; }
    
    NSData *jsonData;
    NSError *error = nil;
    
    NSString *jsonStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    jsonData = [jsonStr dataUsingEncoding:NSUTF8StringEncoding];
    id jsonObject = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingAllowFragments error:&error];
    if (jsonObject == nil) {
        return @"nil (json object from data)";
    } else {
        BOOL isValidJsonObject = [NSJSONSerialization isValidJSONObject:jsonObject];
        if (isValidJsonObject) {
            NSData *finalData = [NSJSONSerialization dataWithJSONObject:jsonObject options:NSJSONWritingPrettyPrinted error:&error];
            //TODO: error description
            NSString *prettyJson = [[NSString alloc] initWithData:finalData encoding:NSUTF8StringEncoding];
            return prettyJson;
        } else {
            return [NSString stringWithFormat:@"%@\n%@", jsonStr, @" (⚠️ Invalid json object ⚠️)\n"];
        }
    }
}

@end

then call methods when u need to use them.

ex1. Print NSData for body, response ...etc

NSLog(@"body: %@", [NSString prettifiedJsonStringFromData:[request HTTPBody]]);

ex2. Print NSDictionary

NSLog(@"headers: %@", [NSString prettifiedStringFromDictionary:[request allHTTPHeaderFields]]);

Probably you'll get these results in log.

enter image description here

enter image description here

Esparza answered 16/7, 2021 at 3:11 Comment(0)
H
-1

I can't think of something prettier than a native type.

if let json = try? JSONSerialization.jsonObject(with: jsonData, options: []) {
    if let jsonArray = json as? [Any] { print(jsonArray) }
    else if let jsonDict = json as? [String:Any] { print(jsonDict) }
    else { print("Couldn't convert json") }
}
Hsu answered 30/4, 2018 at 23:35 Comment(7)
I think the goal of the question is to get pretty printed JSON. This answer does not give you JSON.Christian
If you want to print the representation of something, why does it matter what underlying object gets printed? As long as the output produced faithfully represents the json, it should be fine.Hsu
@BallpointBen, Your code prints array or dictionary, so it doesn't print the real json which comes server side.Illfounded
Seems like a distinction without a difference to me.Hsu
BTW - Inside the 1st if let all you need is print(json).Christian
@BallpointBen, I need to see exact data which comes from server side, not modified.Illfounded
@Illfounded one thing I noticed is that decoding, then re-encoding the values via the JSONSerialization class seems to mess with floats. For instance, my original json had 188.71 as a value, but running it through the encoding, then re-decoding yielded 188.71000000000001. No idea why, but it's pretty frustrating to not get back exactly what went in. Just giving you a heads-up.Crag

© 2022 - 2024 — McMap. All rights reserved.