Java: CSV to XML using Jackson - java

I'm trying to update the following code to output a CSV file into XML. The code below does a brilliant job in converting the CSV to JSON using the headers in the CSV to make the required JSON.
But I want to output as XML instead, and I can't seem to find any good advice to complete this.
Would appreciate some pointers.
package reader;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.databind.MappingIterator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;
public class JacksonPackage
{
public static void main(String[] args) throws Exception
{
File input = new File("c:\\temp\\data.csv");
File output = new File("c:\\temp\\data.json");
List<Map<?, ?>> data = readObjectsFromCsv(input);
writeAsJson(data, output);
}
public static List<Map<?, ?>> readObjectsFromCsv(File file)
throws IOException
{
CsvSchema bootstrap = CsvSchema.emptySchema().withHeader();
CsvMapper csvMapper = new CsvMapper();
MappingIterator<Map<?, ?>> mappingIterator = csvMapper
.reader(Map.class).with(bootstrap).readValues(file);
return mappingIterator.readAll();
}
public static void writeAsJson(List<Map<?, ?>> data, File file)
throws IOException
{
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(file, data);
}
}

Isn't it just a matter of replacing ObjectMapper with XmlMapper?

Related

How to show on the web json

I'm using java spring boot i can print json result on the terminal but i want to show on the web so how can i change this code it to show on web
package com.tutorial.springboot;
import com.google.gson.Gson;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
import lombok.var;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.sql.Driver;
public class Application {
public static void main(String[] args) throws IOException, ClassNotFoundException{
var prop = new Properties();
prop.load(new FileInputStream("src/main/resources/Application.properties"));
var ds = new SimpleDriverDataSource();
ds.setDriverClass(((Class<Driver>) Class.forName(prop.getProperty("jdbc.driver"))));
ds.setUrl(prop.getProperty("jdbc.url"));
ds.setUsername(prop.getProperty("jdbc.username"));
ds.setPassword(prop.getProperty("jdbc.password"));
var sql = "SELECT * FROM ked_evaluation_data";
var jtm = new JdbcTemplate(ds);
List<Map<String, Object>> rows = (List<Map<String, Object>>) jtm.queryForList(sql);
Gson gson = new Gson();
String jcart=gson.toJson(rows);
System.out.println(jcart);
//rows.forEach(System.out::println);
}
}
In summary, i want to know how to change the code to show the result on web
If someone knows that please teach me!! thank you!
You need to use Spring boot rest controller here like below
#RestController
public class HelloController {
#RequestMapping("/json")
public String index() {
var prop = new Properties();
prop.load(new FileInputStream("src/main/resources/Application.properties"));
var ds = new SimpleDriverDataSource();
ds.setDriverClass(((Class<Driver>) Class.forName(prop.getProperty("jdbc.driver"))));
ds.setUrl(prop.getProperty("jdbc.url"));
ds.setUsername(prop.getProperty("jdbc.username"));
ds.setPassword(prop.getProperty("jdbc.password"));
var sql = "SELECT * FROM ked_evaluation_data";
var jtm = new JdbcTemplate(ds);
List<Map<String, Object>> rows = (List<Map<String, Object>>) jtm.queryForList(sql);
Gson gson = new Gson();
String jcart=gson.toJson(rows);
return jcart;
}
}
Application.java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Call it from the web using url like http://localhost:8080/json
(Replace host and port, also to use rest controller you may need to add dependencies if not already present)
Hope this helps

How to use indentation in gson to generate a json file

I have to generate a json file containing indentation. I was using Jackson for this but it adds a space before the colon and I don't need it, so I decided to use Gson.
After changing the code, I figured out that by default Gson don't use indentation but Jackson does. Does anyone know if it is possible in Gson to get indentation and how to do it?
For generating the json file with Gson I made this:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder = gsonBuilder.setPrettyPrinting();
Gson gson = gsonBuilder.create();
Writer writer = new FileWriter(propsFile);
gson.toJson(properties, writer);
You can only employ the default indentation provided by setPrettyPrinting() and you cannot change its size or indentation characters. Please refer to the official information about it: Compact Vs. Pretty Printing for JSON Output Format.
Possible duplicate of https://stackoverflow.com/a/41509714/4379906
Use Jackson and and configure it not to add spaces before colon:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.2</version>
</dependency>
CustomPrettyPrinter.java:
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import java.io.IOException;
class CustomPrettyPrinter extends DefaultPrettyPrinter {
public CustomPrettyPrinter() {
super();
}
public CustomPrettyPrinter(DefaultPrettyPrinter base) {
super(base);
}
#Override
public void writeObjectFieldValueSeparator(JsonGenerator g) throws IOException {
g.writeRaw(": ");
}
#Override
public DefaultPrettyPrinter createInstance() {
return new CustomPrettyPrinter(this);
}
}
UseJackson.java:
import com.fasterxml.jackson.core.util.DefaultIndenter;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
import java.io.IOException;
import java.util.Properties;
public class UseJackson {
public static void main(String[] args) throws IOException {
DefaultPrettyPrinter.Indenter indenter = new DefaultIndenter(" ", DefaultIndenter.SYS_LF);
DefaultPrettyPrinter printer = new CustomPrettyPrinter();
printer.indentArraysWith(indenter);
printer.indentObjectsWith(indenter);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setDefaultPrettyPrinter(printer);
Properties properties = new Properties();
properties.put("foo", "3");
properties.put("bar", "4");
objectMapper.writerWithDefaultPrettyPrinter().writeValue(new File("a.json"), properties);
}
}
Use Gson and configure indentation:
UseGson.java:
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.stream.JsonWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
public class UseGson {
public static void main(String[] args) throws IOException {
Properties properties = new Properties();
properties.put("foo", "3");
properties.put("bar", "4");
JsonWriter jsonWriter = new JsonWriter(new FileWriter("a.json"));
jsonWriter.setIndent(" ");
Gson gson = new GsonBuilder().serializeNulls().create();
gson.toJson(properties, Properties.class, jsonWriter);
jsonWriter.close();
}
}

EDI Must be a minimum of 1 instances of segment [UNS]

Am newbie to EDI. And i just converted the ORDERS edi file to XML using smooks api. Some of the ORDER example files are working fine in following example. But i got the following exception when i running the following edi file. Am stuck with this. Here is my example and EDI data
package example;
import org.json.JSONObject;
import org.json.XML;
import org.milyn.Smooks;
import org.milyn.SmooksException;
import org.milyn.io.StreamUtils;
import org.milyn.smooks.edi.unedifact.UNEdifactReaderConfigurator;
import org.xml.sax.SAXException;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.StringWriter;
public class Main {
public static int PRETTY_PRINT_INDENT_FACTOR = 4;
protected static String runSmooksTransform() throws IOException, SAXException, SmooksException {
Smooks smooks = new Smooks();
smooks.setReaderConfig(new UNEdifactReaderConfigurator("urn:org.milyn.edi.unedifact:d93a-mapping:*"));
try {
StringWriter writer = new StringWriter();
smooks.filterSource(new StreamSource(new FileInputStream("EDI.edi")), new StreamResult(writer));
return writer.toString();
} finally {
smooks.close();
}
}
public static void main(String[] args) throws IOException, SAXException, SmooksException {
System.out.println("\n\n==============Message In==============");
System.out.println(readInputMessage());
System.out.println("======================================\n");
String messageOut = Main.runSmooksTransform();
System.out.println("==============Message Out=============");
System.out.println(messageOut);
System.out.println("======================================\n\n");
JSONObject xmlJSONObj = XML.toJSONObject(messageOut);
String jsonPrettyPrintString = xmlJSONObj.toString(PRETTY_PRINT_INDENT_FACTOR);
System.out.println(jsonPrettyPrintString);
}
private static String readInputMessage() throws IOException {
return StreamUtils.readStreamAsString(new FileInputStream("EDI.edi"));
}
}
And the exception with Sample EDI Data
Exception in thread "main" org.milyn.SmooksException: Failed to filter source.
at org.milyn.delivery.sax.SmooksSAXFilter.doFilter(SmooksSAXFilter.java:97)
at org.milyn.delivery.sax.SmooksSAXFilter.doFilter(SmooksSAXFilter.java:64)
at org.milyn.Smooks._filter(Smooks.java:526)
at org.milyn.Smooks.filterSource(Smooks.java:482)
at org.milyn.Smooks.filterSource(Smooks.java:456)
at example.Main.runSmooksTransform(Main.java:49)
at example.Main.main(Main.java:63)
Caused by: org.milyn.edisax.EDIParseException: EDI message processing failed [ORDERS][D:93A:UN]. Must be a minimum of 1 instances of segment [UNS]. Currently at segment number 9.
at org.milyn.edisax.EDIParser.mapSegments(EDIParser.java:499)
at org.milyn.edisax.EDIParser.mapSegments(EDIParser.java:450)
at org.milyn.edisax.EDIParser.parse(EDIParser.java:426)
at org.milyn.edisax.EDIParser.parse(EDIParser.java:410)
at org.milyn.edisax.unedifact.handlers.UNHHandler.process(UNHHandler.java:97)
at org.milyn.edisax.unedifact.handlers.UNBHandler.process(UNBHandler.java:75)
at org.milyn.edisax.unedifact.UNEdifactInterchangeParser.parse(UNEdifactInterchangeParser.java:113)
at org.milyn.smooks.edi.unedifact.UNEdifactReader.parse(UNEdifactReader.java:75)
at org.milyn.delivery.sax.SAXParser.parse(SAXParser.java:76)
at org.milyn.delivery.sax.SmooksSAXFilter.doFilter(SmooksSAXFilter.java:86)
... 6 more
Bad source data will cause this.
It looks like smooks is looking for a UNS segment which isn't in your data. The section control is mandatory per the D.93A standard.

marshal Object to CSV

I'm trying to marshal an Object into a csv String. I have created a method that can convert any object into a csv String but I keep getting the exception:
java.lang.NoSuchMethodError: org.codehaus.jackson.map.ObjectMapper.writer(Lorg/codehaus/jackson/FormatSchema;)Lorg/codehaus/jackson/map/ObjectWriter;
Marshal method:
public static final synchronized String marshal(final Object object, final CsvSchema csvSchema) throws IOException {
String CSV_FILTER_NAME = "csvFilter";
HashSet<String> columnNames = new HashSet<>();
for (CsvSchema.Column column : csvSchema) {
columnNames.add(column.getName());
}
SimpleBeanPropertyFilter csvReponseFilter = new SimpleBeanPropertyFilter.FilterExceptFilter(columnNames);
FilterProvider filterProvider = new SimpleFilterProvider().addFilter(CSV_FILTER_NAME, csvReponseFilter);
CsvMapper csvMapper = new CsvMapper();
csvMapper.setFilters(filterProvider);
csvMapper.setAnnotationIntrospector(new JacksonAnnotationIntrospector() {
#Override
public Object findFilterId(AnnotatedClass annotatedClass) {
return CSV_FILTER_NAME;
}
});
ObjectWriter objectWriter = csvMapper.writer(csvSchema);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
objectWriter.writeValue(byteArrayOutputStream, csvSchema);
return new String(byteArrayOutputStream.toByteArray(), "UTF-8");
}
Main method:
public static void main(String args[]) {
CsvSchema csvSchema = CsvSchema.builder()
.addColumn("name")
.addColumn("age")
.addColumn("height")
.addColumn("weight")
.setUseHeader(true)
.build()
.withLineSeparator("\n");
Person person = new Person("Tim", "32", "184", "100");
try {
System.out.println(CsvUtilities.marshal(person, csvSchema));
} catch (IOException ex) {
Logger.getLogger(CsvUtilities.class.getName()).log(Level.SEVERE, null, ex);
}
}
What is causing this exception?
EDIT Here's all my imports:
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.List;
import java.util.logging.Logger;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.codehaus.jackson.map.ObjectWriter;
import org.codehaus.jackson.map.introspect.AnnotatedClass;
import org.codehaus.jackson.map.introspect.JacksonAnnotationIntrospector;
import org.codehaus.jackson.map.ser.FilterProvider;
import org.codehaus.jackson.map.ser.impl.SimpleBeanPropertyFilter;
import org.codehaus.jackson.map.ser.impl.SimpleFilterProvider;
See the jars in your class path. It could be that there are two or different version of jackson jar which does not have this method. Maybe an older version been laoded in by the Class loader.
Also inspect your dependencies which you have added to the project.

Using builder to create nested XML

I'm using the Jackson set of classes to read in a CSV file, and convert it to xml, but need some advice on how to add a nested value.
The code I'm using is:
package reader;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.databind.MappingIterator;
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
public class Mustang
{
public static void main(String[] args) throws Exception
{
// Define the input file
File input = new File("c:\\temp\\all_idocs.csv");
// Define the output file
File output = new File("c:\\temp\\all_idocs.xml");
System.out.println("INFO: Commencing Conversion");
List<Map<?, ?>> data = readObjectsFromCsv(input); // readObjectsFromCSV(input
// file name)
System.out.println(readObjectsFromCsv(input));
writeAsXml(data, output); // writeAsXml function, to output location
System.out.println("INFO: Conversion Complete");
}
public static List<Map<?, ?>> readObjectsFromCsv(File file)
throws IOException
{
CsvSchema schema = CsvSchema.builder()
.addColumn("A0001")
.addColumn("A0186")
.addColumn("A0187")
.addColumn("A0352")
.addColumn("A0539")
.addColumn("A0963")
.addColumn("A1046")
.addColumn("A0792")
.addColumn("A0218")
.addColumn("A0584")
.addColumn("A0016")
.addColumn("A0017")
.addColumn("A0478")
.addColumn("A0051")
.addColumn("A0052")
.addColumn("A0053")
.addColumn("A0059")
.addColumn("A0440")
.addColumn("A0054")
.addColumn("A0055")
.addColumn("A0056")
.addColumn("A0057")
.addColumn("A0058")
.addColumn("A1128")
.addColumn("A0003")
.addColumn("A0069")
.addColumn("A0070")
.addColumn("A0074")
.addColumn("A0073")
.addColumn("A0071")
.addColumn("A0110")
.addColumn("A0109")
.addColumn("A0108")
.build();
CsvMapper csvMapper = new CsvMapper();
MappingIterator<Map<?, ?>> mappingIterator = csvMapper
.reader(Map.class).with(schema).readValues(file); // Change the "with()" to pull in the schema
return mappingIterator.readAll();
}
public static void writeAsXml(List<Map<?, ?>> data, File file)
throws IOException
{
XmlMapper mapper = new XmlMapper();
mapper.writeValue(file, data);
}
}
If I run this against a CSV file, I get output similar to this:
<item>
<A0001>J1000097</A0001>
<A0186>5028197000004</A0186>
<A0187>1</A0187>
<A0352></A0352>
<A0539>00</A0539>
<A0963>20050209</A0963>
</item>
I want to see if it's possible to indent/nest some of these attributes, to produce something like this:
<item>
<A0001>J1000097</A0001>
<A0186>5028197000004</A0186>
<A0187>
<A0352>12</A0352>
<A0539>00</A0539>
</A0187>
<A0963>20050209</A0963>
</item>
I'm assuming I must have to do something within the builder section of the code, but as I'm new to using it, I can't fathom out how.
In this case you may want to process Map after reading it from CSV, but before writing it as XML. You can then add a wrapper around values you want to group. That is, something like:
Map<?,?> value = ... ; // individual row
Map<String,Object> wrapped = new LinkedHashMap<>();
wrapped.put("A0352", value.remove("A0352"));
wrapped.put("A0539", value.remove("A0539"));
value.put("A0187", wrapped);
another possibility would be to use value conversion between Map, and POJO type that uses #JsonUnwrapped to handle grouping.
Conversion itself may be done using:
MyPOJO value = mapper.convertValue(map, MyPOJO.class); // and/or reverse
but this approach may become more complicated.

Categories

Resources