Reputation: 4739
I'm using the JSON in Java for the transformation of XML to JSON. I have the problem that this implementation is inverting all child elements.
When I pass this XML:
<Person><Child1>a</Child1><Child2>b</Child2></Person>
I will end up with a JSON having the childs inverted:
{"Person":{"Child2":"b", "Child1":"a"}}
My Java code:
JSONObject jsonObject= XML.toJSONObject("<Person><Child1>a</Child1><Child2>b</Child2></Person>");
String myJSONString = jsonObject.toString(4);
How to transform to JSON with keeping the order of the elements (like in XML)?
Upvotes: 11
Views: 8698
Reputation: 21
The best solution to this answer if anyone dont want to change the internal implementation of JSONObject
from HashMap to LInkedHashMap in source code but keep the order of xml to json preserved
is to use the XMLMapper
and JSONMapper
through these 2 dependency
<dependencies>
1.
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.3</version> <!-- Use the latest version bro -->
</dependency>
2.
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.13.3</version> <!-- Use the latest version bro -->
</dependency>
</dependencies>
and we can modify the code as
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import java.io.File;
import java.io.IOException;
public class XmlToJsonConverter {
public static void main(String args[]){
String inputXmlFile = "C://user//your_xml.xml"
String outputJsonFile = "C://user//your_output_json.json"
try {
convertXmlToJson(inputXmlFile, outputJsonFile);
System.out.println("Conversion completed successfully.");
} catch (IOException e) {
e.printStackTrace();
System.err.println("An error occurred during conversion: " + e.getMessage());
}
}
public static void convertXmlToJson(String inputXmlFile, String outputJsonFile) throws IOException {
// Create XmlMapper and ObjectMapper
XmlMapper xmlMapper = new XmlMapper();
ObjectMapper jsonMapper = new ObjectMapper();
// Read XML file and convert to JsonNode
JsonNode jsonNode = xmlMapper.readTree(new File(inputXmlFile));
// Write JsonNode to JSON file
jsonMapper.writerWithDefaultPrettyPrinter().writeValue(new File(outputJsonFile), jsonNode);
}
}
Upvotes: 1
Reputation: 14286
If you would use Jackson for JSON serialization / deserialization you could simply put a @JsonPropertyOrder() annotation on top of your class.
@JsonPropertyOrder({"Child1", "Child2"})
public class Person {
@JsonProperty("Child1")
public String child1;
@JsonProperty("Child2")
public String child2;
}
Upvotes: 0
Reputation: 1
You can download the source code from http://www.json.org/java/ and modify JSONObject.java using TreeMap instead of HashMap.
You also can override method in JSONObject.java
public Iterator<String> keys() {
return this.keySet().iterator();
}
Make sure the Iterator is the one of the sorted keys.
Upvotes: 0
Reputation: 16833
As JSONObject is an unordered collection of name/value pairs, no choice, you have to use a JSONArray.
Here is my solution, modify the XML
class, particularly the method parse
, in order to return JSONArray
for storing child nodes.
My modified class : XML.java
XML input
<Person name="test"><Child1>a</Child1><Child2>b</Child2><Child3></Child3></Person>
Usage :
JSONObject jsonObject= XML.toJSONObject("<Person name=\"test\"><Child1>a</Child1><Child2>b</Child2><Child3></Child3></Person>");
System.out.println(jsonObject);
Out :
{"Person":{"CHILDREN":[{"Child1":"a"},{"Child2":"b"},{"Child3":""}],"name":"test"}}
Conclusion
The children order is kept. Off course this idea can be improved, it's just a POC regarding what can be done, modifying the parser.
Upvotes: 1
Reputation: 871
If you are hell bent on getting the output ordered the way you want it you could always try overriding the method
toString()
Upvotes: 0
Reputation: 109
The JSONObject API dose not guarantee the elements order A nice solution to this issue can be using JSONArray, in JSONArray the order you insert the elements is saved.
So, in your case you will have an array of "chides" for each person. you would probably will need to change the XML file or manually parse the XML into the json in your format (the JSONArray instead of what you are using now)
Upvotes: 0
Reputation: 29999
JSON objects don't have a specific order. You can of course change the serialization implementation to keep an order but there is no guarantee that it is also kept after deserialization. In fact, most JSON libraries won't even have an API to detect in which order the original JSON text was parsed. You shouldn't care about ordering when using objects.
If you do care about the order though, use a JSON array.
{"Person":[{"Child1":"a"},{"Child2":"b"}]}
Upvotes: 0
Reputation: 15821
You can keep order of incoming data when modify
private final Map<String, Object> nameValuePairs;
/**
* Creates a {@code JSONObject} with no name/value mappings.
*/
public JSONObject() {
nameValuePairs = new HashMap<String, Object>();
}
to
private final Map<String, Object> nameValuePairs;
/**
* Creates a {@code JSONObject} with no name/value mappings.
*/
public JSONObject() {
nameValuePairs = new LinkedHashMap<String, Object>();
}
Because instead of HashMap
- LinkedHashMap
have an predictable iteration order.
LinkedHashMap : Hash table and linked list implementation of the Map interface, with predictable iteration order.
So is the most effective way to resolve your problem.
And also you can fork to use a custom library from
Upvotes: -1
Reputation: 1861
So my question. How to transform to JSON with keeping the order?
With the current official JSONObject, this is not possible. The API makes it very clear:
A JSONObject is an unordered collection of name/value pairs.
But, there might be a quick workaround for your problem. As from what I've investigated in the JSONObject source code, you can see that it uses a HashMap internally, and as you know HashMap doesn't keep any order.
public JSONObject() {
this.map = new HashMap<String, Object>();
}
You have 2 alternatives:
Modify the current JSONObject source code so that the map is initialized with a LinkedHashMap. A LinkedHashMap is an implementation of the Map interface, with predictable iteration order:
public JSONObject() {
this.map = new LinkedHashMap<String, Object>();
}
Make your own custom class which extends JSONObject but uses a LinkedHashMap internally. Notice that you still have to make some changes in JSONObject.
public class JSONObject {
//private final Map<String,Object> map; // current approach
//you have to remove final modifier and either add a getter or make it protected. I'll choose the change modifier to protected in this case.
protected Map<String,Object> map;
}
public class JSONObjectOrdered extends JSONObject {
public JSONObjectOrdered(){
this.map = new LinkedHashMap <String, Object>();
}
}
Upvotes: 12