0

I have a JSON object like this:

{
    "shippingLines": [{
        "carrier": "NZ Post",
        "price": {
            "amount": 5.50,
            "currency": "NZD"
        }
    }],
    "taxAmount": {
        "amount": 5.325,
        "currency": "NZD"
    },
    "reference": "INV000045",
    "totalAmount": {
        "amount": 35.5,
        "currency": "NZD"
    },
    "returnUrls": {
        "successUrl": "http://yourserver/success",
        "failUrl": "http://yourserver/fail",
        "callbackUrl": "http://yourserver/fail-safe-callback"
    }
}

I want to strip off all JSON formatting (spaces, comma, parentheses, brackets, quotes, colon) from it and product an output like following:

shippingLinescarrierNZPostpriceamount5.50currencyNZDtaxAmountamount5.325currencyNZDreferenceINV000045totalAmountamount35.5currencyNZDreturnUrlssuccessUrlhttp://yourserver.com/successfailUrlhttp://.yourserver.com/failcallbackUrlhttp://yourserver.com/fail-safe-callback

so I tried a bunch of replaceAll() like below:

String json = objectMapper.writeValueAsString(<Json Class here>); // using Jackson
json.replaceAll("\"", "")
    .replaceAll("\\{","")
    .replaceAll("\\}","")
    .replaceAll("\\[","")
    .replaceAll("\\]","")
    .replaceAll(":","")
    .replaceAll(",","")
    .replaceAll(" ","");

But this also replaced the "colon" in the URL (http://...) in the returnUrls object. Is there a better way to achieve this ?

Note: I'm on Java 7.

Craigo
  • 3,384
  • 30
  • 22
Adhyatmik
  • 1,038
  • 11
  • 19
  • I think you could traverse all values and write the strings to an output stream. – MC Emperor Sep 20 '19 at 05:46
  • Does this answer your question? [Remove white space in Json](https://stackoverflow.com/questions/26678435/remove-white-space-in-json) – Craigo Aug 15 '21 at 10:16

7 Answers7

2

Go char by char. Copying stuff between quotes as is

String json = objectMapper.writeValueAsString(<Json Class here>); // using Jackson
String output = "";
int len = json.length();
boolean inQuotes = false;
for (int i = 0; i < len; i++)
{
    char c = json.charAt(i);
    if (c == '\"')
    {
        inQuotes = !inQuotes;
        continue;
    }
    if (inQuotes)
    {
        output = output + c;
    }
}

There's optimizations with regards to appending to strings, StringBuilder, etc... but the above is the basic gist of it.

As others have pointed out, this doesn't handle the case of an escape sequence within a string:

"A string with an \"escaped\" quote include \u1234 and \b or \t"

I'm going to leave that up you as an exercise.

selbie
  • 100,020
  • 15
  • 103
  • 173
  • 1
    To be technically correct, you probably also have to handle `\\` ( in the case of `\\"`) and converting escaped Unicode to characters. But parsing is already the best answer for this problem, and it works for the Json the OP provided, so have my upvote. – Ferrybig Sep 20 '19 at 06:06
  • @Ferrybig - I was just about to add the inner quote logic, but I think I'm going to leave that as an exercise for the OP to complete. – selbie Sep 20 '19 at 06:09
  • @selbie Thank you for your answer. This works except for the properties like `amount` which is a number, so not in quotes. Hence the parser skips it. – Adhyatmik Sep 20 '19 at 07:20
  • Then you are going to have to traverse the JSON tree object instead of parsing as a string. Otherwise, you'll wind up up writing a json parser yourself to account for all the edge cases. – selbie Sep 20 '19 at 07:21
1

Here's another approach. The idea is to traverse all elements, and return their string representation, with whitespace removed.

// Takes input and returns a string with all elements concatenated.
// withExactBigDecimals(true) makes sure trailing zeros (e.g. 5.50) will be
// preserved
static String toRawConcat(String input) throws IOException {
    ObjectMapper mapper = new ObjectMapper()
        .configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true)
        .configure(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN, true)
        .setNodeFactory(JsonNodeFactory.withExactBigDecimals(true));
    JsonNode node = mapper.readTree(input);
    return nodeToString(node);
}

// Removes whitespaces from a string
static String removeWs(String input) {
    return input.replaceAll("\\s+", "");
}

// Inspects the node type and returns the node contents as a string
private static String nodeToString(JsonNode node) {
    switch (node.getNodeType()) {
        case NULL:
        case BOOLEAN:
        case STRING:
            return removeWs(node.asText());
        case NUMBER:
            return node.decimalValue().toString();
        case ARRAY:
            {
                String s = "";
                Iterator<JsonNode> it = node.elements();
                while (it.hasNext()) {
                    s += nodeToString(it.next());
                }
                return s;
            }
        case OBJECT:
            {
                String s = "";
                Iterator<Entry<String, JsonNode>> it = node.fields();
                while (it.hasNext()) {
                    Entry<String, JsonNode> sub = it.next();
                    s += removeWs(sub.getKey()) + nodeToString(sub.getValue());
                }
                return s;
            }
        default:
            throw new UnsupportedOperationException("Node type " + node.getNodeType() + " not supported");
    }

By the way, if you want to strip just everything that doesn't look like a node value (e.g. you're expecting "NZ Post" to become "NZPost"), why are you parsing it as JSON in the first place?

MC Emperor
  • 22,334
  • 15
  • 80
  • 130
  • Thanks a lot. Exactly what i was looking for ( I was "nearly" there, after reading a ton of jackson tutorial). To answer your Q, I have a `POJO` modeling this json request and I wanted to have a String representation of it, so I could use a `replaceAll()`, so, I used the `writeValueAsString()` method – Adhyatmik Sep 20 '19 at 17:11
0

You can do in three steps, not sure that you have any other case.

Step 1: Replace all http:// to something. For instance, http:__

Step 2: Your current one.

Step 3: Reverse it from step 1.

Tran Ho
  • 1,442
  • 9
  • 15
0

If the issue is strictly the http://, then you could replace http// by the original http://.

   String output1=    json.replaceAll("\"", "")
                    .replaceAll("\\{","")
                    .replaceAll("\\}","")
                    .replaceAll("\\[","")
                    .replaceAll("\\]","")
                    .replaceAll(":","")
                    .replaceAll(",","")
                    .replaceAll(" ","")
                    .replaceAll("\\\\","")
                    .replaceAll("http//", "http://");

Careful though, as this will result in unwanted replacements if your json ever contains a http// that you don't wish to replace.

Arpit Asati
  • 130
  • 2
  • 16
0

You can use regex for it. This will help you.

REGEX [^a-zA-Z0-9-./]

public class Test {

    public static void main(String[] args) {
        String jsonString = "{\n" +
                "    \"shippingLines\": [{\n" +
                "        \"carrier\": \"NZ Post\",\n" +
                "        \"price\": {\n" +
                "            \"amount\": 5.50,\n" +
                "            \"currency\": \"NZD\"\n" +
                "        }\n" +
                "    }],\n" +
                "    \"taxAmount\": {\n" +
                "        \"amount\": 5.325,\n" +
                "        \"currency\": \"NZD\"\n" +
                "    },\n" +
                "    \"reference\": \"INV000045\",\n" +
                "    \"totalAmount\": {\n" +
                "        \"amount\": 35.5,\n" +
                "        \"currency\": \"NZD\"\n" +
                "    },\n" +
                "    \"returnUrls\": {\n" +
                "        \"successUrl\": \"http://yourserver/success\",\n" +
                "        \"failUrl\": \"http://yourserver/fail\",\n" +
                "        \"callbackUrl\": \"http://yourserver/fail-safe-callback\"\n" +
                "    }\n" +
                "}";
        String format = jsonString.replaceAll("[^a-zA-Z0-9-./]", "");
    }
}

Pawan Maurya
  • 387
  • 2
  • 11
0

We can first convert it to yaml, then replacing would be more easier and generic. Like here

import java.io.IOException;

import org.springframework.util.StringUtils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;

public class Library {

    public static String asYaml(String jsonString) throws JsonProcessingException, IOException {
        // parse JSON
        JsonNode jsonNodeTree = new ObjectMapper().readTree(jsonString);
        // save it as YAML
        String jsonAsYaml = new YAMLMapper().writeValueAsString(jsonNodeTree);
        return jsonAsYaml;
    }
    public static void main(String[] args) {
        String jsonStr = "{\r\n" + 
                "    \"shippingLines\": [{\r\n" + 
                "        \"carrier\": \"NZ Post\",\r\n" + 
                "        \"price\": {\r\n" + 
                "            \"amount\": 5.50,\r\n" + 
                "            \"currency\": \"NZD\"\r\n" + 
                "        }\r\n" + 
                "    }],\r\n" + 
                "    \"taxAmount\": {\r\n" + 
                "        \"amount\": 5.325,\r\n" + 
                "        \"currency\": \"NZD\"\r\n" + 
                "    },\r\n" + 
                "    \"reference\": \"INV000045\",\r\n" + 
                "    \"totalAmount\": {\r\n" + 
                "        \"amount\": 35.5,\r\n" + 
                "        \"currency\": \"NZD\"\r\n" + 
                "    },\r\n" + 
                "    \"returnUrls\": {\r\n" + 
                "        \"successUrl\": \"http://yourserver/success\",\r\n" + 
                "        \"failUrl\": \"http://yourserver/fail\",\r\n" + 
                "        \"callbackUrl\": \"http://yourserver/fail-safe-callback\"\r\n" + 
                "    }\r\n" + 
                "}";
        try {
            String ymlstr = asYaml(jsonStr);
            System.out.println(ymlstr);
            ymlstr=StringUtils.replace(ymlstr, ":", "");
            ymlstr=StringUtils.replace(ymlstr, "-", "");
            ymlstr=StringUtils.replace(ymlstr, "\n", "");
            ymlstr=StringUtils.replace(ymlstr, " ", "");
            ymlstr=StringUtils.replace(ymlstr, "\"", "");
            System.out.println(ymlstr);
        } catch (JsonProcessingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
} 

Maven dependencies:

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.8.6</version>
</dependency>
    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.8.6</version>
</dependency>
    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-yaml -->
<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-yaml</artifactId>
    <version>2.8.6</version>
</dependency>

Output:

shippingLinescarrierNZPostpriceamount5.5currencyNZDtaxAmountamount5.325currencyNZDreferenceINV000045totalAmountamount35.5currencyNZDreturnUrlssuccessUrlhttp//yourserver/successfailUrlhttp//yourserver/failcallbackUrlhttp//yourserver/failsafecallback
madhepurian
  • 271
  • 1
  • 13
-1

To remove colon after key First remove only

":

After completion get new string. Now remove

"

Suman Kumar Dash
  • 681
  • 5
  • 19