Java - processing Marklogic eval response giving JSON Documents - java

I have a MarkLogic XQuery eval call that returns a lists of strings. I use the below code to process the results. I have another call that returns a list of Json Documents but I can't see how to get EvalResult to give me a JsonDocument document. How do I change the below code to process Json Documents?
public static ArrayList<String> getStringList(DatabaseClient client, String query)
{
ArrayList<String> strings = new ArrayList<String>();
ServerEvaluationCall eval = client.newServerEval();
EvalResultIterator eri = eval.xquery(query).eval();
while (eri.hasNext())
{
EvalResult er = eri.next();
String s = er.getString();
strings.add(s);
}
return strings;
}

First, let me suggest that you only use eval as a last resort as it may open a security hole. Injection attacks aren't possible if you never send code from the client to be executed on the server. Start first with the out-of-the-box features, and if those aren't enough, consider writing a resource extension instead of using eval. Two examples are ResourceExtension and JavascriptResourceExtension.
But to answer your question, change this:
String s = er.getString();
to this:
JacksonHandle handle = er.get(new JacksonHandle());
JsonNode json = handle.get();
or this shortcut:
JsonNode json = er.getAs(JsonNode.class);
For a complete example, see handling of myArray and myObject EvalTest.evalAndInvokeXQuery (and of course, runAndTestXQuery) and evaltest.xqy.
These Jackson handles work the same whether you're getting JSON results from a document read, search, or eval. You can read more about the io shortcuts here. For more sample code with Jackson, see JacksonHandleExample, JacksonHandleTest, JacksonStreamTest, and JacksonDatabindTest.

Related

Parsing a text file using java with multiple values per line to be extracted

I'm not going to lie I'm really bad at making regular expressions. I'm currently trying to parse a text file that is giving me a lot of issues. The goal is to extract the data between their respective "tags/titles". The file in question is a .qbo file laid out as follows personal information replaced with "DATA": The parts that I care about retrieving are between the "STMTTRM" and "/STMTTRM" tags as the rest I don't plan on putting in my database, but I figured it would help others see the file content I'm working with. I apologize for any confusion prior to this update.
FXHEADER:100
DATA:OFXSGML
VERSION:102
SECURITY:NONE
ENCODING:USASCII
CHARSET:1252
COMPRESSION:NONE
OLDFILEUID:NONE
NEWFILEUID:NONE
<OFX>
<SIGNONMSGSRSV1><SONRS>
<STATUS><CODE>0</CODE><SEVERITY>INFO</SEVERITY></STATUS>
<DTSERVER>20190917133617.000[-4:EDT]</DTSERVER>
<LANGUAGE>ENG</LANGUAGE>
<FI>
<ORG>DATA</ORG>
<FID>DATA</FID>
</FI>
<INTU.BID>DATA</INTU.BID>
<INTU.USERID>DATA</INTU.USERID>
</SONRS></SIGNONMSGSRSV1>
<BANKMSGSRSV1>
<STMTTRNRS>
<TRNUID>0</TRNUID>
<STATUS><CODE>0</CODE><SEVERITY>INFO</SEVERITY></STATUS>
<STMTRS>
<CURDEF>USD</CURDEF>
<BANKACCTFROM>
<BANKID>DATA</BANKID>
<ACCTID>DATA</ACCTID>
<ACCTTYPE>CHECKING</ACCTTYPE>
<NICKNAME>FREEDOM CHECKING</NICKNAME>
</BANKACCTFROM>
<BANKTRANLIST>
<DTSTART>20190717</DTSTART><DTEND>20190917</DTEND>
<STMTTRN><TRNTYPE>POS</TRNTYPE><DTPOSTED>20190717071500</DTPOSTED><TRNAMT>-5.81</TRNAMT><FITID>3893120190717WO</FITID><NAME>DATA</NAME><MEMO>POS Withdrawal</MEMO></STMTTRN>
<STMTTRN><TRNTYPE>DIRECTDEBIT</TRNTYPE><DTPOSTED>20190717085000</DTPOSTED><TRNAMT>-728.11</TRNAMT><FITID>4649920190717WE</FITID><NAME>CHASE CREDIT CRD</NAME><MEMO>DATA</MEMO></STMTTRN>
<STMTTRN><TRNTYPE>ATM</TRNTYPE><DTPOSTED>20190717160900</DTPOSTED><TRNAMT>-201.99</TRNAMT><FITID>6674020190717WA</FITID><NAME>DATA</NAME><MEMO>ATM Withdrawal</MEMO></STMTTRN>
</BANKTRANLIST>
<LEDGERBAL><BALAMT>2024.16</BALAMT><DTASOF>20190917133617.000[-4:EDT]</DTASOF></LEDGERBAL>
<AVAILBAL><BALAMT>2020.66</BALAMT><DTASOF>20190917133617.000[-4:EDT]</DTASOF></AVAILBAL>
</STMTRS>
</STMTTRNRS>
</BANKMSGSRSV1>
</OFX>
I want to be able to end with data that looks or acts like the following so that each row of data can easily be added to a database:
Example Parse
As David has already answered, It is good to parse the POS output XML using Java. If you are more interested about about regex to get all the information, you can use this regular expression.
<[^>]+>|\\n+
You can test in the following sites.
https://rubular.com/
https://www.regextester.com/
Given this is XML, I would do one of two things:
either use the Java DOM objects to marshall/unmarshall to/from Java objects (nodes and elements), or
use JAXB to achieve something similar but with better POJO representation.
Mkyong has tutorials for both. Try the dom parsing or jaxb. His tutorials are simple and easy to follow.
JAXB requires more work and dependencies. So try DOM first.
I would propose the following approach.
Read file line by line with Files:
final List<String> lines = Files.readAllLines(Paths.get("/path/to/file"));
At this point you would have all file line separated and ready to convert the string lines into something more useful. But you should create class beforehand.
Create a class for your data in line, something like:
public class STMTTRN {
private String TRNTYPE;
private String DTPOSTED;
...
...
//constructors
//getters and setters
}
Now when you have a data in each separate string and a class to hold the data, you can convert lines to objects with Jackson:
final XmlMapper xmlMapper = new XmlMapper();
final STMTTRN stmttrn = xmlMapper.readValue(lines[0], STMTTRN.class);
You may want to create a loop or make use of stream with a mapper and a collector to get the list of STMTTRN objects:
final List<STMTTRN> stmttrnData = lines.stream().map(this::mapLine).collect(Collectors.toList());
Where the mapper might be:
private STMTTRN mapLine(final String line) {
final XmlMapper xmlMapper = new XmlMapper();
try {
return xmlMapper.readValue(line, STMTTRN.class);
} catch (IOException e) {
throw new RuntimeException(e);
}
}

Pretty print for JSON in Java works fine for the console, but in browser it does not work

I have a JSON file and I want to retrieve its content from a API call within a rest controller created in Java Spring Boot.
I get the content of the .json file into a String and use the below method ( one of them ) in order to pretty print.
If I system.out.println() the output, it gets pretty printed, but in the browser it is displayed roughly and with no indentation. I had more approaches :
String content = new String(Files.readAllBytes(resource.toPath()));
Gson gson = new GsonBuilder().setPrettyPrinting().create();
JsonParser jp = new JsonParser();
JsonElement je = jp.parse(content);
String prettyJsonString = gson.toJson(je);
System.out.println(prettyJsonString);
return prettyJsonString;
The other approach returns the same ugly output in browser, but it also adds "/r/n":
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
String prettyJsonString = mapper.writeValueAsString(content);
return prettyJsonString;
Can anyone help me get the pretty output in browser as well?
Formatting String for console output and for HTML output are two VERY different tasks. Method setPrettyPrinting() is for console printing. HTML browser will ignore "\n" symbols and will not respect multiple spaces replacing them with a single space etc. In general, it is usually a client-side task to format the output. But I delt once with this problem and wrote a method that takes a console-formatted string and converts it to Html formatted String. For instance, it replaces all "\n" symbols with br Html tags. It does some other things as well. I had some success with it, but sometimes some unexpected problems occurred. You are welcome to use it. The method is available in MgntUtils Open source library. Here is its JavaDoc. The library itself is available as Maven artifact here and on Github (including source code and JavaDoc) here. An article about the library is here. Your code would look like this:
String htmlString = TextUtils.formatStringToPreserveIndentationForHtml(jsonPrettyString);
I had this same problem and stumbled upon how to get it to pretty print in the browser.
In your application.properties file, add these two lines:
# Preferred JSON mapper to use for HTTP message conversion.
spring.mvc.converters.preferred-json-mapper=gson
# Whether to output serialized JSON that fits in a page for pretty printing.
spring.gson.pretty-printing=true
Reference: https://www.callicoder.com/configuring-spring-boot-to-use-gson-instead-of-jackson/
Maybe related: https://stackoverflow.com/a/62044963

Access fields of returned Java Object

I made a simple client call to the XML-RPC WordPress API/Posts using a xml-rpc client and according to their documentation here it returns a struct. How can i access the return values.
Here is a look at my code:
XmlRpcClient client = new XmlRpcClient("http://www.mywebsite.net/xmlrpc.php", false);
String[] fields = new String[4];
fields[0] = "post_id";
fields[1] = "post_title";
fields[2] = "post_date";
fields[3] = "post_content";
Object token = client.invoke("wp.getPost", new Object[]{"0","myusername", "mypassword", 1545, fields });
System.out.println(token);
When I print use
System.out.println(token);
I get the following out put:
{item_one=I am item number one, item_two=I am Item two...}
How can I access item_one and item_two?
There's a bit of information missing (what's the fully qualified name of XmlRpcClient?), but assuming that client.invoke actually returns just an Object and not something more specific that has accessor methods, you can parse the response using something like this:
Object token = client.invoke("wp.getPost", new Object[]{"0","myusername", "mypassword", 1545, fields });
String[] items = token.toString().split(",");
for (String item : items) {
String[] parts = item.split("=");
String key = parts[0];
String value = parts[1];
// do stuff with your keys and values here
}
Of course this isn't perfect code -- you may need to check for nulls, use String.trim(), etc, but it should get you started.
You don't have a true Java representation of the data returned, in that you don't have an object on which you can access
token.item_one
rather you have a string containing a representation of a set - that is something that (in concept) from which you could retrieve an value by its name
token.get("item_one")
This string format is probably JSON, which pretty much looks like JavaScript, and hence can represent quite complex data. In general you can have arrays of objects and objects containing objects (for example, a Customer might contain an Address object)
So you have two possibilities:
1). parse the string into a true Java representation such as one of the standard Java collection classes. You then use the get-by-name style I show above.
2). define a Java class that mimics the structure of the data and then parse the string to fill out such an object, you can then use the "dot" form of access - you really have a Java Object representing the data.
In the first case there are suitable libraries such as quickJson
For the second you can use implementations of standards such as JAX/B, which tends to be more work as you may need to construct the target Java Class by hand. Enterprise Java runtimes will give you these facilities and perhaps tooling to help, or look at implementaitons such as Jackson. You will see that JAX/B hada focus on mapping from XML to Java, but tutorials such as this show how to work with JSON instead.
My guess is that the first option, simple parsing to a collection may be enough for you.

JSon to CSV with Java using CDL: possible to replace comma-sep. by semi-colum sep. values?

Everything is in the title :)
I'm using org.json.CDL to convert JSONArray into CSV data but it renders a string with ',' as separator.
I'd like to know if it's possible to replace with ';' ?
Here is a simple example of what i'm doing:
public String exportAsCsv() throws Exception {
return CDL.toString(
new JSONArray(
mapper.writeValueAsString(extractAccounts()))
);
}
Thanks in advance for any advice on that question.
Edit: No replacement solution of course, as this could have impact for large data, and of course the library used enable me to specify the field separator.
Edit2: Finally the solution to extract data as JSONArray (and String...) was not very good, especially for large data file.
So i made the following changes:
use a Java CSV library (for example: http://www.csvreader.com/java_csv_samples.php)
refactor code to stream data from json input source to csv output source
This is nicer for large data treatment. If you have comments do not hesitate.
String output = "Hello,This,is,separated,by,a,comma";
// Simple call the replaceAll method.
output = output.replace(',',';');
I found this in the String documentation.
Example
String value = "Hello,tthis,is,a,string";
value = value.replace(',', ';');
System.out.println(value);
// Outputs: Hello;tthis;is;a;string

How to create a JSONArray that contains Javascript code inside Java?

I am creating a JSONArray and parse it to a String, but as it even contains Strings instead of code it doesn't output as I need it.
for(Place place: places){
locations.put("new google.maps.LatLng("+place.getContactData().getLatitude()+","+place.getContactData().getLongitude()+")");
}
return locations.toString();
It outputs as: ["new google.maps.LatLng(53.5608,9.96357)","new google.maps.LatLng(53.5608,9.96357)"] but I need it without quotation marks like [new google.maps.LatLng(53.5608,9.96357),new google.maps.LatLng(53.5608,9.96357)] to be correctly interpreted by javascript.
Another method would be:
create an array with just the coordinates:
for(Place place: places){
JSONObject obj = new JSONObject();
obj.put("lat",place.getContactData().getLatitude());
obj.put("lng",place.getContactData().getLongitude());
locations.put(obj);
}
and then in javascript:
var places = (yourPlacesJson);
var placeObjects = [];
for(var i=0;i<places.length;i++)
{
placeObjects[placeObjects.length] = new google.maps.LatLng(places[i].lat,places[i].lng);
}
JSON only supports plain-old-data. It can't include any executable code (a new is executable code). This is by design - when JSON would be able to include executable code you would have to be much more carefully with importing JSON from an untrusted source.
All you can do is pass javascript code as strings and eval() it on the JS side after parsing the JSON.
Also you could use Regular expressions to remove the ", if you parse the json to another language
i had a similar problem, the way i made this work:
instead of writing the javascript before the json conversion, insert a placeholder.
locations.put("%mapsPlaceholder1%");
then after filling the array with placeholders, do:
locations.toString().replaceFirst("\"%mapsPlaceholder1%\"","yourJsCode");
something like that
you could also just create the array string manually

Categories