I have written a Groovy that have as an input an xml file and i want to extract the value of two tags that are part of the xml file.I have converted XML to Json and from JSON to Map. This Java code works for me:
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import org.apache.commons.io.IOUtils;
import org.json.JSONObject;
import org.json.XML;
import com.bfi.digi.chk.CheckRemittance;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
CheckRemittance remise =data;
InputStream inputStream = new FileInputStream(new File(
"C:/xml/full_rejection_notification.xml"));
String xml = IOUtils.toString(inputStream);
JSONObject jObject = XML.toJSONObject(xml);
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
Object json = mapper.readValue(jObject.toString(), Object.class);
String output = mapper.writeValueAsString(json);
Map<String, List<String>> response = new ObjectMapper().readValue(output, HashMap.class);
String state= response.get("Document").get("FIToFIPmtStsRpt").get("TxInfAndSts").get("TxSts").toString();
String errorCode=response.get("Document").get("FIToFIPmtStsRpt").get("TxInfAndSts").get("StsRsnInf").get("Rsn").get("Cd").toString();
return state.concat(" ").concat(errorCode);
The problem is that i'm getting an xml file containing repetitive block and as Map don't allow duplicate key I have to find another solution. I'm looking for your propositions.
Related
How is arbitrary JSON converted to arbitrary XML using BaseX?
I'm looking at JsonParser from BaseX for this specific solution.
In this case, I have tweets using Twitter4J:
package twitterBaseX;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.logging.Logger;
import main.LoadProps;
import org.basex.core.BaseXException;
import twitter4j.JSONException;
import twitter4j.JSONObject;
import twitter4j.Query;
import twitter4j.QueryResult;
import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.TwitterObjectFactory;
import twitter4j.conf.ConfigurationBuilder;
public class TwitterOps {
private static final Logger log = Logger.getLogger(TwitterOps.class.getName());
public TwitterOps() {
}
private TwitterFactory configTwitterFactory() throws IOException {
LoadProps loadTwitterProps = new LoadProps("twitter");
Properties properties = loadTwitterProps.loadProperties();
log.fine(properties.toString());
ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
configurationBuilder.setDebugEnabled(true)
.setJSONStoreEnabled(true)
.setOAuthConsumerKey(properties.getProperty("oAuthConsumerKey"))
.setOAuthConsumerSecret(properties.getProperty("oAuthConsumerSecret"))
.setOAuthAccessToken(properties.getProperty("oAuthAccessToken"))
.setOAuthAccessTokenSecret(properties.getProperty("oAuthAccessTokenSecret"));
return new TwitterFactory(configurationBuilder.build());
}
public List<JSONObject> getTweets() throws TwitterException, IOException, JSONException {
Twitter twitter = configTwitterFactory().getInstance();
Query query = new Query("lizardbill");
QueryResult result = twitter.search(query);
String string = null;
JSONObject tweet = null;
List<JSONObject> tweets = new ArrayList<>();
for (Status status : result.getTweets()) {
tweet = jsonOps(status);
tweets.add(tweet);
}
return tweets;
}
private JSONObject jsonOps(Status status) throws JSONException, BaseXException {
String string = TwitterObjectFactory.getRawJSON(status);
JSONObject json = new JSONObject(string);
String language = json.getString("lang");
log.fine(language);
return json;
}
}
The JSONObject from Twitter4J cannot just get jammed into XML?
There are a number of online converters which purport to accomplish this, and, which, at least at first glance, seem quite adequate.
see also:
Converting JSON to XML in Java
Java implementation of JSON to XML conversion
Use the (excellent) JSON-Java library from json.org then
JSONObject json = new JSONObject(str);
String xml = XML.toString(json);
toString can take a second argument to provide the name of the XML root node.
This library is also able to convert XML to JSON using XML.toJSONObject(java.lang.String string)
Check the Javadoc for more information
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.
I'm having a little bit trouble with freemarker right now. What I want to do basically in my template: iterate over a list of elements and create for each element a new file.
<#assign x=3>
<#list 1..x as i>
${i}
...create a new file with the output of this loop iteration...
</#list>
I did not find anything about this in the freemarker manual or google. Is there a way to do this?
You can implement this with a custom directive. See freemarker.template.TemplateDirectiveModel, and particularly TemplateDirectiveBody. Custom directives can specify the Writer used in their nested content. So you can do something like <#output file="...">...</#output>, where the nested content will be written into the Writer you have provided in your TemplateDirectiveModel implementation, which in this case should write into the file specified. (FMPP does this too: http://fmpp.sourceforge.net/qtour.html#sect4)
You cannot do this using only FreeMarker. Its idea is to produce the single output stream from your template. It doesn't even care whether you will save the result to file, pass directly to TCP socket, store in the memory as string or do anything else.
If you really want to achieve this, you have to handle file separation by yourself. For example, you can insert special line like:
<#assign x=3>
<#list 1..x as i>
${i}
%%%%File=output${i}.html
...
</#list>
After that you should post-process FreeMarker output by yourself looking for the lines started with %%%%File= and create a new file at this point.
As ddekany said, you can do that implementing a directive. I have coded a little example:
package spikes;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;
import freemarker.core.Environment;
import freemarker.template.Configuration;
import freemarker.template.SimpleScalar;
import freemarker.template.Template;
import freemarker.template.TemplateDirectiveBody;
import freemarker.template.TemplateDirectiveModel;
import freemarker.template.TemplateException;
import freemarker.template.TemplateModel;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
class OutputDirective implements TemplateDirectiveModel {
#Override
public void execute(
Environment env,
#SuppressWarnings("rawtypes") Map params,
TemplateModel[] loopVars,
TemplateDirectiveBody body)
throws TemplateException, IOException {
SimpleScalar file = (SimpleScalar) params.get("file");
FileWriter fw = new FileWriter(new File(file.getAsString()));
body.render(fw);
fw.flush();
}
}
public class FreemarkerTest {
public static void main(String[] args) throws Exception {
Configuration cfg = new Configuration(Configuration.VERSION_2_3_0);
cfg.setDefaultEncoding("UTF-8");
JsonObject model = new JsonObject()
.put("entities", new JsonArray()
.add(new JsonObject()
.put("name", "Entity1"))
.add(new JsonObject()
.put("name", "Entity2")));
Template template = new Template("Test", "<#assign model = model?eval_json><#list model.entities as entity><#output file=entity.name + \".txt\">This is ${entity.name} entity\n</#output></#list>", cfg);
Map<String, Object> root = new HashMap<String, Object>();
root.put("output", new OutputDirective());
root.put("model", model.encode());
Writer out = new OutputStreamWriter(System.out);
template.process(root, out);
}
}
This will generate two files:
"Entity1.txt": This is Entity1 entity
"Entity2.txt": This is Entity2 entity
:-)
I have a code that parses through XML files, edits them and saves them (using dom for this). Now, I have a few files which have the .ftl extension. I have managed to process the ftl file with given answers (using freemarker template configuration) , However, I am unable to save the edited xml back as an FTL.
All of this is in Java. Any suggestions on how I can achieve the saving aspect of the problem?
Again, I want to process, edit and then save an FTL file in Java.
I am appending the code that I have for processing the ftl file.
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.stream.JsonReader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
public class FTLReader {
public static void main(String[] args) {
//Freemarker configuration object
Configuration cfg = new Configuration();
try {
//Load template from source folder
Template template = cfg.getTemplate(filename);
// Build the data-model
Map<String,Object> data = new HashMap<String,Object>();
JsonParser parser = new JsonParser();
//write code to get answers
Object obj = parser.parse(new FileReader("src/answers.txt"));
JsonObject jsonObject = (JsonObject) obj;
data.put("element1", jsonObject.get("element1"));
// Console output
Writer out = new OutputStreamWriter(System.out);
template.process(data, out);
out.flush();
/*write code to edit and save the ftl file
*
*
*
*
* */
// File output (the processed FTL file)
Writer file = new FileWriter (new File("C:\\FTL_helloworld.txt"));
template.process(data, file);
file.flush();
file.close();
} catch (IOException e) {
e.printStackTrace();
} catch (TemplateException e) {
e.printStackTrace();
}
}
}
After reading your question and comments few times, I am probably finally getting to grasp what you are aiming to. So, you have to "patch" the file behind the filename variable from the start of your code (Template template = cfg.getTemplate(filename);). FTL file is basically a text file, so you can process it line by line. Then you must re-initialize your template with the new file content, i.e. do template = cfg.getTemplate(filename); again.
Please have a look at the following.
import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONML;
import org.json.JSONTokener;
import org.json.XML;
import com.amazonaws.auth.ClasspathPropertiesFileCredentialsProvider;
import com.amazonaws.regions.Region;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.GetObjectRequest;
import com.amazonaws.services.s3.model.S3Object;
public class JsonToXML
{
private AmazonS3Client s3;
public JsonToXML(String inputBucket, String inputFile) throws IOException, JSONException
{
//Connection to S3
s3 = new AmazonS3Client(new ClasspathPropertiesFileCredentialsProvider());
Region usWest2 = Region.getRegion(Regions.US_EAST_1);
s3.setRegion(usWest2);
//Downloading the Object
System.out.println("Downloading Object");
S3Object s3Object = s3.getObject(new GetObjectRequest(inputBucket, inputFile));
System.out.println("Content-Type: " + s3Object.getObjectMetadata().getContentType());
//Read the JSON File
BufferedReader reader = new BufferedReader(new InputStreamReader(s3Object.getObjectContent()));
StringBuffer strBuffer = new StringBuffer("");
int i=0;
while (true) {
String line = reader.readLine();
if (line == null) break;
System.out.println("Running: "+i);
strBuffer.append(line);
i++;
}
JSONTokener jTokener = new JSONTokener(strBuffer.toString());
JSONArray jsonArray = new JSONArray(jTokener);
//Convert to XML
String xml = XML.toString(jsonArray);
File f = new File("XML.xml");
FileWriter fw = new FileWriter(f);
fw.write(xml);
}
}
This is how the Json files look like
[
{
"_type": "ArticleItem",
"body": "Who's signing",
"source": "money.cnn.com",
"last_crawl_date": "2014-01-14",
"url": "http: //money.cnn.com/"
},
{
"_type": "ArticleItem",
"body": "GMreveals",
"title": "GMreveals625-horsepowerCorvetteZ06-Jan.13",
"source": "money.cnn.com",
"last_crawl_date": "2014-01-14",
"url": "http: //money.cnn.com"
}
]
This code generated invalid XML or files without any text. Invalid means, after the last <> it still generate some text, so the entire file is invalid. What is wrong here?
UPDATE
According to the answer of jtahlborn I managed to generate an XML file with the following output.
<array><body>Who's signing</body><_type>ArticleItem</_type><source>money.cnn.com</source><last_crawl_date>2014-01-14</last_crawl_date><url>http: //money.cnn.com/</url></array><array><body>GMreveals</body><_type>ArticleItem</_type><title>GMreveals625-horsepowerCorvetteZ06-Jan.13</title><source>money.cnn.com</source><last_crawl_date>2014-01-14</last_crawl_date><url>http: //money.cnn.com</url></array>
But XML Validator in here says:
XML Parsing Error: junk after document element
Location: http://www.w3schools.com/xml/xml_validator.asp
Line Number 1, Column 181:
You need to flush()/close() the FileWriter to ensure all the data is written to the file.
The problem is that you have 2 "top-level" elements in your xml result (2 "array" elements). xml can only have one top-level element.
UPDATE:
Try this for converting the json to xml:
String xml = XML.toString(jsonArray, "doc");