0

I am trying to convert the large JSON/JSON-LD file to XML. The JSON file will contain a list of events (not all events are the same and each may have different information/data). I would like to read the events one by one and store the information in a single Object (rather than having different objects for each event). I would like to store it in the form of Parent and Children. As soon as I read one event I would like to convert it to JSON then go to the next one.

I am looking into JACKSON and seems like it fits this. However, I am looking into this particular class TokenBuffer which is actually kind of doing the same. It's reading the JSON file line by line and then trying to see if the incoming element is Array or Object based on that it's making various decisions.

I wanted to confirm if I can use this Class directly to pass my JsonFile and get the Parent and child relationship which will be stored in JsonWriteContext later I can convert it to XML.

Basically, my sample file will have many events in the JSON which I would like to read one by one and then get the element info and its parent-children relationship in a Single Object such as maybe HashMap.

BATMAN_2008
  • 2,788
  • 3
  • 31
  • 98

1 Answers1

0

After trying some of the things following is my code which will contain the Parent and Child elements from Json:

@Getter
@Setter
@NoArgsConstructor
public class JsonContext {
    private JsonContext parent;
    private String key;
    private String value;
    private int childCount;
    private Map<String, List<JsonContext>> children = new HashMap<String, List<JsonContext>>();

    // Constructor for Children Object
    JsonContext(String key, String value) {
        this.key = key;
        this.value = value;
    }

    // Constructor for Parent Object
    JsonContext(JsonContext parent, String key, String value) {
        this(key, value);
        this.parent = parent;
    }

    // Add child based on incoming element
    public JsonContext addChild(JsonContext context) {
        List<JsonContext> childValues = children.get(context.getKey());
        if (childValues == null) {
            childValues = new ArrayList<JsonContext>();
        }
        childValues.add(context);
        children.put(context.key, childValues);
        childCount++;
        return context;
    }

    // Get the parent and their subsequent children (test purpose only)
    @Override
    public String toString() {
        String s = key + children.entrySet().stream().map(e -> e.getKey() + " -- " + String.join(", ", e.getValue().stream().map(v -> v.toString())
                            .collect(Collectors.toList()))).collect(Collectors.toList());

        if (value.length() > 0) {
            final String chars = value.toString().trim();
            if (chars.length() > 0) {
                s = s + " = " + chars;
            }
        }
        return s;
    }

}

The above is the context file that will store the information. Below is the JSON parser file.

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Arrays;

import com.converter.xml2jsonld.test.JSONParser;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;

public class JsonEventsParser {

    private JsonContext context = null;
    private final String[] eventTypes = new String[] { "event1", "event2", "event3", "event4",
                        "event5" };

    public void jsonFileIterator() throws URISyntaxException, JsonParseException, IOException {
        // Get the JSON Factory and parser Object
        JsonFactory jsonFactory = new JsonFactory();
        JsonParser jsonParser = jsonFactory.createParser(new File(JSONParser.class.getClassLoader().getResource("inputJsonFile.json").toURI()));
        JsonToken current = jsonParser.nextToken();

        // Check the first element is Object
        if (current != JsonToken.START_OBJECT) {
            throw new IllegalStateException("Expected content to be an array");
        }

        // Call the method to loop until the end of the events file
        FileNavigator(jsonParser);
    }

    private void FileNavigator(JsonParser jsonParser) throws IOException {

        JsonToken current = jsonParser.getCurrentToken();

        // Loop until the end of the EPCIS events file
        while (jsonParser.nextToken() != JsonToken.END_OBJECT) {

            final JsonToken token = jsonParser.nextToken();
            final String name = jsonParser.getCurrentName();

            // Handling the fields with direct key value pairs
            if ((token == JsonToken.FIELD_NAME || token == JsonToken.VALUE_STRING)) {
                writeFieldName(jsonParser, token);
            }

            // Handling the Object
            if (token == JsonToken.START_OBJECT) {
                writeObjectFields(jsonParser, token);
            }

            // Handling the Array
            if (token == JsonToken.START_ARRAY) {
                writeArrayFields(jsonParser, token);
            }

            if (context != null) {
                if (context.getParent() != null) {
                    context = context.getParent();
                }
            }
        }
        System.out.println(context.getChildren().toString());
    }

    // Method to obtain the STRING field and write into Context
    private void writeFieldName(JsonParser jsonParser, JsonToken token) throws IOException {
        final String key = jsonParser.getCurrentName();
        final String value = jsonParser.getValueAsString();

        // Check for the eventType
        if (context == null && Arrays.asList(eventTypes).contains(value)) {
            context = new JsonContext(key, value);
        } else if (context != null) {
            context = context.addChild(new JsonContext(context, key, value));
        }

    }

    // Method to obtain the OBJECT and write its children into Context
    private void writeObjectFields(JsonParser jsonParser, JsonToken token) throws IOException {

        final String objectParent = jsonParser.getCurrentName() == null ? context.getParent().getKey() : jsonParser.getCurrentName();
        // Add the name of the OBJECT
        if (context == null) {
            context = new JsonContext(jsonParser.getCurrentName(), "Object");
        } else if (context != null) {
            context = context.addChild(new JsonContext(context, objectParent, "Object"));
        }

        token = jsonParser.nextToken();

        // Loop through all elements within OBJECT and add them to its parent
        while (token != JsonToken.END_OBJECT) {
            final String key = jsonParser.getCurrentName();
            token = jsonParser.nextToken();
            // Check for incoming tokens within array and process accordingly
            switch (token) {
            case START_ARRAY:
                writeArrayFields(jsonParser, token);
                break;
            case START_OBJECT:
                writeObjectFields(jsonParser, token);
                break;
            default:
                final String value = jsonParser.getText();
                context = context.addChild(new JsonContext(context, key, value));
                break;
            // throw new RuntimeException("Object : Elements does not match the type
            // (Method: writeObjectFields)");
            }

            context = context.getParent();
            token = jsonParser.nextToken();
        }
    }

    // Method to Obtain the ARRAY and write its children into Context
    private void writeArrayFields(JsonParser jsonParser, JsonToken token) throws IOException {

        final String arrayField = jsonParser.getCurrentName();
        // Add the name of the ARRAY
        if (context == null) {
            context = new JsonContext(arrayField, "Array");
        } else if (context != null) {
            context = context.addChild(new JsonContext(context, arrayField, "Array"));
        }

        token = jsonParser.nextToken();

        // Loop through all ARRAY elements
        while (token != JsonToken.END_ARRAY) {

            switch (token) {
            case START_OBJECT:
                writeObjectFields(jsonParser, token);
                break;
            case VALUE_STRING:
                context = context.addChild(new JsonContext(context, arrayField, jsonParser.getText()));
                break;
            case START_ARRAY:
                writeArrayFields(jsonParser, token);
                break;
            default:
                throw new RuntimeException("Array : Elements does not match the type (Method: writeArrayFields)");
            }

            context = context.getParent();
            token = jsonParser.nextToken();
        }
    }
}
BATMAN_2008
  • 2,788
  • 3
  • 31
  • 98
  • There are easier ways to manipulate the JSON using JACKSON2. Why are choosing the `JSONParsor`? Do you have any specific requirments?? – Avinash Apr 22 '21 at 06:34
  • The only requirement is that I do not want to load the complete JSON file into the memory. I would like to read the events in JSON one by one so at a time only one event is present in memory which I can process and proceed to the next one in a similar manner until the end of the file. Since the events can be complex and can be of different type I am using a single context rather than multiple classes each for a different events. Can you please guide me over some other approach that is more easy and efficient? – BATMAN_2008 Apr 22 '21 at 07:33