Convert directory as string to json array node - java

Given this list as array of strings:
Cars/Truck/Regular
Cars/Truck/4x4/Lifted
Cars/Jeep/4x4
Cars/Convertable
How do I parse this into json like:
[{"name":"Cars","nodes":[{"name":"Truck","nodes":[{"name":"Regular","nodes":[]},{"name":"4x4","nodes":[{"name":"Lifted","nodes":[]}]}]},{"name":"Jeep","nodes":[{"name":"4x4","nodes":[]}]},{"name":"Convertable","nodes":[]}]}]
So far this all I have for recursive going through. Now will have to figure out the node class part.
String[] li = new String[4];
li[0] = "Cars/Truck/Regular";
li[1] = "Cars/Truck/4x4/Lifted";
li[2] = "Cars/Jeep/4x4";
li[3] = "Cars/Convertable";
doAll(li);
public void doAll(String[] files) {
try {
for (String file : files) {
String[] f = file.split("/");
if (f.length>1) {
logger.info("directory:"+file);
f = (String[]) ArrayUtils.removeElement(f, f[0]);
String temp = "";
for(String ff : f) temp=temp+"/"+ff;
temp = temp.replaceFirst("/", "");
doAll(new String[]{temp});
} else if(f.length==1){
logger.info("file:"+file);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
produces:
directory:Cars/Truck/Regular
directory:Truck/Regular
file:Regular
directory:Cars/Truck/4x4/Lifted
directory:Truck/4x4/Lifted
directory:4x4/Lifted
file:Lifted
directory:Cars/Jeep/4x4
directory:Jeep/4x4
file:4x4
directory:Cars/Convertable
file:Convertable

Probably you have to create a structure to holding those data first, then feed all data into the structure, serialize the result to json string at end. Pseudo code something like:
class Node {
String name;
List<Node> nodes; // sub nodes
/*
Add new node under current node.
*/
public void addNode(Node node) {...}
}
You start from the very first value say Car to create the structure, then try to recursively find left values say /Truck, /Truck/Regular in it's sub (or sub's sub) nodes. If found, do nothing, else you create a new sub node and add it to the node you last found.

Related

Converting binary response from JInterface Java app back into list of strings in Elixir

I have a small java app and I have used JInterface to essentially expose it as an OTP process in my elixir app. I can call it and get a response successfully.
My problem is that the response I get back in elixir is of a binary but I cannot figure out how to convert a binary to a list of strings which is what the response is.
The code for my OTP node in Java using JInterface is below:
public void performAction(Object requestData, OtpMbox mbox, OtpErlangPid lastPid){
List<String> sentences = paragraphSplitter.splitParagraphIntoSentences((String) requestData, Locale.JAPAN);
mbox.send(lastPid, new OtpErlangBinary(getOtpStrings(sentences)));
System.out.println("OK");
}
private List<OtpErlangString> getOtpStrings(List<String> sentences) {
List<OtpErlangString> erlangStrings = new ArrayList<>();
for(int i = 0; i < sentences.size(); i++){
erlangStrings.add(new OtpErlangString(sentences.get(i)));
}
return erlangStrings;
}
It is necessary to wrap the response in an OtpErlangBinary and I have concerted the strings to OTPErlangString. I have also tried without converting the strings to OTPErlangString.
On the elixir side I can receive the binary response and IO.inspect it.
Does anybody know how to use JInterface to deserialise the results correctly when it's anything other than a single string? Or maybe, if I have made some mistake, how to build the correct response type so that I can deserialise it correctly?
Any help would be really appreciated as I have been trying to figure this out for ages.
Thanks in advance.
I have been playing around with JInterface and Elixir and I think I've got your problem figured out.
So you are trying to send a list of strings from an Elixir/Erlang node to a Java node, but you cannot get it to de-serialize properly.
Elixir has its own types (e.g., atoms, tuples, ..) and Java has its own types (e.g., Object, String, List<String>,..). There needs to be a conversion from the one type to the other if they're supposed to talk to each other. In the end it's just a bunch of 1's and 0's that get sent over the wire anyway.
If an Erlang list is sent to Java, what arrives can always be interpreted as an OtpErlangObject. It's up to you to then try and guess what the actual type is before we can even begin turning it into a Java value.
// We know that everything is at least an OtpErlangObject value!
OtpErlangObject o = mbox.receive();
But given that you know that it's in fact a list, we can turn it into an OtpErlangList value.
// We know o is an Erlang list!
OtpErlangList erlList = (OtpErlangList) o;
The elements of this list however, are still unknown. So at this point its still a list of OtpErlangObjects.
But, we know that it's a list of strings, so we can interpret the list of OtpErlangObjects as list of OtpErlangStrings, and convert those to Java strings.
public static List<String> ErlangListToStringList(OtpErlangList estrs) {
OtpErlangObject[] erlObjs = estrs.elements();
List<String> strs = new LinkedList<String>();
for (OtpErlangObject erlO : erlObjs) {
strs.add(erlO.toString());
}
return strs;
}
Note that I used the term list here a lot, because it's in fact an Erlang list, in Java it's all represented as an array!
My entire code is listed below.
The way to run this is to paste it into a Java IDE, and start a REPL with the following parameters:
iex --name bob#127.0.0.1 --cookie "secret"
Java part:
import com.ericsson.otp.erlang.*;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
public class Main {
public static OtpErlangList StringListToErlangList(List<String> strs) {
OtpErlangObject[] elems = new OtpErlangObject[strs.size()];
int idx = 0;
for (String str : strs) {
elems[idx] = new OtpErlangString(str);
idx++;
}
return new OtpErlangList(elems);
}
public static List<String> ErlangListToStringList(OtpErlangList estrs) {
OtpErlangObject[] erlObjs = estrs.elements();
List<String> strs = new LinkedList<String>();
for (OtpErlangObject erlO : erlObjs) {
strs.add(erlO.toString());
}
return strs;
}
public static void main(String[] args) throws IOException, InterruptedException {
// Do some initial setup.
OtpNode node = new OtpNode("alice", "secret");
OtpMbox mbox = node.createMbox();
mbox.registerName("alice");
// Check that the remote node is actually online.
if (node.ping("bob#127.0.0.1", 2000)) {
System.out.println("remote is up");
} else {
System.out.println("remote is not up");
}
// Create the list of strings that needs to be sent to the other node.
List<String> strs = new LinkedList<String>();
strs.add("foo");
strs.add("bar");
OtpErlangList erlangStrs = StringListToErlangList(strs);
// Create a tuple so the other node can reply to use.
OtpErlangObject[] msg = new OtpErlangObject[2];
msg[0] = mbox.self();
msg[1] = erlangStrs;
OtpErlangTuple tuple = new OtpErlangTuple(msg);
// Send the tuple to the other node.
mbox.send("echo", "bob#127.0.0.1", tuple);
// Await the reply.
while (true) {
try {
System.out.println("Waiting for response!");
OtpErlangObject o = mbox.receive();
if (o instanceof OtpErlangList) {
OtpErlangList erlList = (OtpErlangList) o;
List<String> receivedStrings = ErlangListToStringList(erlList);
for (String s : receivedStrings) {
System.out.println(s);
}
}
if (o instanceof OtpErlangTuple) {
OtpErlangTuple m = (OtpErlangTuple) o;
OtpErlangPid from = (OtpErlangPid) (m.elementAt(0));
OtpErlangList value = (OtpErlangList) m.elementAt(1);
List<String> receivedStrings = ErlangListToStringList(value);
for (String s : receivedStrings) {
System.out.println(s);
}
}
} catch (OtpErlangExit otpErlangExit) {
otpErlangExit.printStackTrace();
} catch (OtpErlangDecodeException e) {
e.printStackTrace();
}
}
}
}

Jacskon XML serialization of a list

EDIT: I am trying to serialise to XML markup from Java objects.
I am struggling to serialise some XML from a List of size N of Integers using Jackson.
I want to output the following XML from a list of integers of variable length [9, 2, ... , 7].
<tagName>
<thing1>9</thing1>
<thing2>2</thing2>
...
<thingN>7</thingN>
<tagName>
I can't find any resource on here for dealing with deserialising lists.
The closest I have managed to get is
#JacksonXmlProperty(localName = "thing")
private List<Integer> thingList;
And I can't figure out how to add a counter to the local name for each member of the list.
Any help would be appreciated, thank you!
Ok Now I got your problem. So We I tried It with Jsoup library and find below code snippet for your work.
public static void main(String[] args) {
int [] array={1,2,3,4,5};
TagName name = new TagName();
//initialize the TagName object
for (int a=0;a<array.length;a++) {
name.setThingList(array[a]);
}
XmlMapper xmlMapper = new XmlMapper();
try {
//get object as a string
String value = xmlMapper.writeValueAsString(name);
//First you need to parse the xml
Document doc = Jsoup.parse(value, "", Parser.xmlParser());
//get tagname object
Element tagname = doc.getElementsByTag("tagname").first();
//get tagname's children which are thing
Elements childs = tagname.children();
for (int a = 0; a < childs.size(); ) {
//rename their tagname
childs.get(a).tagName("thing" + ++a);
}
System.out.println(tagname);
} catch (IOException e) {
e.printStackTrace();
}
}
<tagname>
<thing1>
1
</thing1>
<thing2>
2
</thing2>
<thing3>
3
</thing3>
<thing4>
4
</thing4>
<thing5>
5
</thing5>
</tagname>
#JacksonXmlRootElement(localName = "xml")
public class TagName {
public ArrayList<Integer> getThingList() {
return thingList;
}
public void setThingList(Integer thing) {
this.thingList.add(thing);
}
#JacksonXmlElementWrapper(localName = "tagname")
#JacksonXmlProperty(localName = "thing")
private ArrayList<Integer> thingList = new ArrayList<>();
}

Java Milo OPC-UA add node

I'm using Milo and its example server and client. I'm adding nodes to the server but I can't figure out how to add EuInformation, i.e., unit and description. I thought about using the ExtensionObject but since EuInformation does not implement Serializable I don't know how to pass it to the ExtensionObject. I'd also like to know how I can get the namespace ID and URI on client side. So far I just set them statically as I have access to the classes.
I've implemeted the AddNodes on server side. I can add nodes, read nodes and write to nodes.
Here's what I'm doing on client side:
// Should somehow get the namespace ID and namespace dynamically.
// Maybe by iterating through all nodes??
ExpandedNodeId parentNodeId = new ExpandedNodeId(
new nodeId(2,DatatypeNamespace.NODE_IDENTIFIER),
datatypeNamespace.NAMESPACE_URI, 0);
NodeId referenceTypeId = Identifiers.String;
// Define the new node.
ExpandedNodeId requestedNewNodeId = new ExpandedNodeId(new NodeId(2, "NewNode"),
DatatypeNamespace.NAMESPACE_URI, 0);
QualifiedName browseName = new QualifiedName(2, "NewNode");
// How to get this to the server??
EUInformation euinfo = new EUInformation(null,-1,LocalizedText.english("MyUnit"),
LocalizedText.english("My Description"));
ExpandedNodeId typeDef = new ExpandedNodeId(Identifiers.BaseVariableType,
DatatypeNamespace.NAMESPACE_URI, 0);
AddNodesItem newItem = new AddNodesItem(parentNodeId, referenceTypeId,
requestedNewNodeId,rowseName,NodeClass.VariableType, null, typeDef);
List<AddNodesItem> items = new ArrayList<AddNodesItem>();
items.add(newItem);
client.addNodes(items).get();
EDIT
With the help of Kevin Herron's answer I worked something out: I adjusted the write() in my namespace class. I can now modify the display name and description of the node with the values of the EUInformation. Here's my write() method:
#Override
public void write(WriteContext context, List<WriteValue> writeValues) {
List<StatusCode> results = Lists.newArrayListWithCapacity(writeValues.size());
for (WriteValue writeValue : writeValues) {
ServerNode node = server.getNodeMap().get(writeValue.getNodeId());
if (node != null) {
// Get the type of the variant thats about to be written to the node
NodeId variantType = writeValue.getValue().getValue().getDataType().get();
if (variantType.equals(Identifiers.Structure)) {
ExtensionObject o = (ExtensionObject) writeValue.getValue().getValue().getValue();
if (o.getEncodingTypeId().equals(Identifiers.EUInformation_Encoding_DefaultBinary)) {
EUInformation euInformation = (EUInformation) o.decode();
node.setDescription(euInformation.getDescription());
node.setDisplayName(euInformation.getDisplayName());
System.out.println("Wrote EUInformation " + euInformation);
results.add(StatusCode.GOOD);
context.complete(results);
return;
}
}
try {
node.writeAttribute(new AttributeContext(context), writeValue.getAttributeId(),
writeValue.getValue(), writeValue.getIndexRange());
results.add(StatusCode.GOOD);
System.out.println(String.format("Wrote value %s to %s attribute of %s",
writeValue.getValue().getValue(),
AttributeId.from(writeValue.getAttributeId()).map(Object::toString).orElse("unknown"),
node.getNodeId()));
} catch (UaException e) {
System.out.println(String.format("Unable to write %s", writeValue.getValue()));
results.add(e.getStatusCode());
}
} else {
results.add(new StatusCode(StatusCodes.Bad_NodeIdUnknown));
}
}
context.complete(results);
}
Ok, so you would add a new VaribleNode with a TypeDefinition of Property (Identifiers.PropertyType).
Then you would write to its Value attribute so it contains the EUInformation object:
EUInformation euInformation = ...
Variant v = new Variant(ExtensionObject.encode(euInformation));
...write the value to the node you created...

Java: Append key value pair to nested json object

I am given three inputs .
A JSON object (nested)
A node structure
key value pair
My task is to append the key value pair to a node by looking at the node structure and updating the original JSON.
For example, if the inputs are,
JSON Object
{
a:
{
b:
{
c:{}
}
}
}
Node structure
a.b.
Key k and value v
The final updated JSON should look like
{
a:
{
b:
{
key:val
c:{}
}
}
}
Please note that the original JSON can be {} also. Then I have to build the whole JSON by looking at the node structure.
Here is my code
making a key value pair
public JSONObject makeEV(String ele, String val) throws JSONException{
JSONObject json =new JSONObject();
json.put(ele, val);
return json;
}
Appending it to JSON
public void modifiedJSON(JSONObject orgJson, String nodeStruct, JSONObject ev) throws JSONException{
JSONObject newJson = new JSONObject();
JSONObject copyJson = newJson;
char last = nodeStruct.charAt(nodeStruct.length()-1);
String lastNode = String.valueOf(last);
int i = 0;
while(orgJson.length() != 0 || i< nodeStruct.length()){
if(orgJson.length() ==0){
if(nodeStruct.charAt(i) == last){
newJson.put(String.valueOf(last), ev.toString());
}else{
newJson.put(String.valueOf(nodeStruct.charAt(i)), "");
}
newJson = newJson.getJSONObject(String.valueOf(nodeStruct.charAt(i)));
}
else if(i >= nodeStruct.length()){
if(orgJson.has(lastNode)){
newJson.put(String.valueOf(last), ev.toString());
}else{
}
}
}
}
I am stuck here. Please help. Thanks in advance.
It could be done using String#split(regex) as next:
public void modifiedJSON(JSONObject orgJson, String nodeStruct,
String targetKey, String value) {
// Split the keys using . as separator
String[] keys = nodeStruct.split("\\.");
// Used to navigate in the tree
// Initialized to the root object
JSONObject target = orgJson;
// Iterate over the list of keys from the first to the key before the last one
for (int i = 0; i < keys.length - 1; i++) {
String key = keys[i];
if (!target.has(key)) {
// The key doesn't exist yet so we create and add it automatically
target.put(key, new JSONObject());
}
// Get the JSONObject corresponding to the current key and use it
// as new target object
target = target.getJSONObject(key);
}
// Set the last key
target.put(targetKey, value);
}

Java sanitizing Arraylist records suggestions

I am looking for an idea how to accomplish this task. So I'll start with how my program is working.
My program reads a CSV file. They are key value pairs separated by a comma.
L1234456,ygja-3bcb-iiiv-pppp-a8yr-c3d2-ct7v-giap-24yj-3gie
L6789101,zgna-3mcb-iiiv-pppp-a8yr-c3d2-ct7v-gggg-zz33-33ie
etc
Function takes a file and parses it into an arrayList of String[]. The function returns the ArrayList.
public ArrayList<String[]> parseFile(File csvFile) {
Scanner scan = null;
try {
scan = new Scanner(csvFile);
} catch (FileNotFoundException e) {
}
ArrayList<String[]> records = new ArrayList<String[]>();
String[] record = new String[2];
while (scan.hasNext()) {
record = scan.nextLine().trim().split(",");
records.add(record);
}
return records;
}
Here is the code, where I am calling parse file and passing in the CSVFile.
ArrayList<String[]> Records = parseFile(csvFile);
I then created another ArrayList for files that aren't parsed.
ArrayList<String> NotParsed = new ArrayList<String>();
So the program then continues to sanitize the key value pairs separated by a comma. So we first start with the first key in the record. E.g L1234456. If the record could not be sanitized it then it replaces the current key with "CouldNOtBeParsed" text.
for (int i = 0; i < Records.size(); i++) {
if(!validateRecord(Records.get(i)[0].toString())) {
Logging.info("Records could not be parsed " + Records.get(i)[0]);
NotParsed.add(srpRecords.get(i)[0].toString());
Records.get(i)[0] = "CouldNotBeParsed";
} else {
Logging.info(Records.get(i)[0] + " has been sanitized");
}
}
Next we do the 2nd key in the key value pair e.g ygja-3bcb-iiiv-pppp-a8yr-c3d2-ct7v-giap-24yj-3gie
for (int i = 0; i < Records.size(); i++) {
if(!validateRecordKey(Records.get(i)[1].toString())) {
Logging.info("Record Key could not be parsed " + Records.get(i)[0]);
NotParsed.add(Records.get(i)[1].toString());
Records.get(i)[1] = "CouldNotBeParsed";
} else {
Logging.info(Records.get(i)[1] + " has been sanitized");
}
}
The problem is that I need both keyvalue pairs to be sanitized, make a separate list of the keyValue pairs that could not be sanitized and a list of the ones there were sanitized so they can be inserted into a database. The ones that cannot will be printed out to the user.
I thought about looping thought the records and removing the records with the "CouldNotBeParsed" text so that would just leave the ones that could be parsed. I also tried removing the records from the during the for loop Records.remove((i)); However that messes up the For loop because if the first record could not be sanitized, then it's removed, the on the next iteration of the loop it's skipped because record 2 is now record 1. That's why i went with adding the text.
Atually I need two lists, one for the Records that were sanitized and another that wasn't.
So I was thinking there must be a better way to do this. Or a better method of sanitizing both keyValue pairs at the same time or something of that nature. Suggestions?
Start by changing the data structure: rather than using a list of two-element String[] arrays, define a class for your key-value pairs:
class KeyValuePair {
private final String key;
private final String value;
public KeyValuePair(String k, String v) { key = k; value = v; }
public String getKey() { return key; }
public String getValue() { return value; }
}
Note that the class is immutable.
Now make an object with three lists of KeyValuePair objects:
class ParseResult {
private final List<KeyValuePair> sanitized = new ArrayList<KeyValuePair>();
private final List<KeyValuePair> badKey = new ArrayList<KeyValuePair>();
private final List<KeyValuePair> badValue = new ArrayList<KeyValuePair>();
public ParseResult(List<KeyValuePair> s, List<KeyValuePair> bk, List<KeyValuePair> bv) {
sanitized = s;
badKey = bk;
badValue = bv;
}
public List<KeyValuePair> getSanitized() { return sanitized; }
public List<KeyValuePair> getBadKey() { return badKey; }
public List<KeyValuePair> getBadValue() { return badValue; }
}
Finally, populate these three lists in a single loop that reads from the file:
public static ParseResult parseFile(File csvFile) {
Scanner scan = null;
try {
scan = new Scanner(csvFile);
} catch (FileNotFoundException e) {
???
// Do something about this exception.
// Consider not catching it here, letting the caller deal with it.
}
final List<KeyValuePair> sanitized = new ArrayList<KeyValuePair>();
final List<KeyValuePair> badKey = new ArrayList<KeyValuePair>();
final List<KeyValuePair> badValue = new ArrayList<KeyValuePair>();
while (scan.hasNext()) {
String[] tokens = scan.nextLine().trim().split(",");
if (tokens.length != 2) {
???
// Do something about this - either throw an exception,
// or log a message and continue.
}
KeyValuePair kvp = new KeyValuePair(tokens[0], tokens[1]);
// Do the validation on the spot
if (!validateRecordKey(kvp.getKey())) {
badKey.add(kvp);
} else if (!validateRecord(kvp.getValue())) {
badValue.add(kvp);
} else {
sanitized.add(kvp);
}
}
return new ParseResult(sanitized, badKey, badValue);
}
Now you have a single function that produces a single result with all your records cleanly separated into three buckets - i.e. sanitized records, records with bad keys, and record with good keys but bad values.

Categories