Possible to use regex with JSON and AJAX? - json

The Problem
Within an AJAX call, I am trying to retrieve a JSON object with an appended auto-generated identifier. Is it possible to use regex to select a JSON object that starts with a specific string?
E.g. below targeting announcements_414988813
jQuery
const parent = $('.c-banner');
let data;
$.getJSON('path_to_data.json', function (result) {
const data = result["jcr:content"]["parsys"];
const announcement = data["/^/announcements"];
let date = announcement.eventDate;
let _html = "";
_html += '<p>' + date + '</p>';
parent.append(_html);
});
JSON
{
"jcr:content": {
"parsys": {
"announcements_414988813": {
"eventDate": "Fri Jan 18 2019 00:00:00 GMT-1000",
"title": "Pizza Day!",
}
}
}
}

After you've extracted the data object, you should be able to loop through its keys and find the one that matches.
var announcement = {}
for (key in data) {
if (key.match(/^announcements/)) {
announcement = data[key];
}
}
Note that if your parsys object has multiple announcements, this would give you the last one. announcement will just remain an empty object if it doesn't find any. (Break out of the loop if you want the first one, or save them all in an array if you need them all.)

Related

Accessing array elements in a vertx JsonObject

Given the following io.vertx.core.json.JsonObject:
{
"111":[
{
"A":"a1",
},
{
"A":"a2",
},
{
"A":"a3",
}
],
"222":[
{
"A":"a10",
},
{
"A":"a20",
},
{
"A":"a30",
}
]
}
As the name of the outer elements which contain arrays (111 and 222) are not known in advance, what is the correct way to access the elements of each array, e.g.
{"A":"a1"}
Once the elements of the array are available as a collection, how can that collection be turned into an rxJava Observable.
Have tried the following:
List list = arrayElements.stream().collect(Collectors.toList());
Observable observable = Observable.fromIterable(list);
However, the issue is that each element in the stream is then represented as a java.util.LinkedHashMap.Entry, e.g. A=a1, whereas what is required is to retain the original Json representation.
Thanks
You can get object fields with JsonObject.fieldNames().
JsonArray is an Iterable<Object> because it may contain different types (objects, strings, ...etc). If you are confident that a JsonArray only contains JsonObject, you could cast the value.
Here's the result combined:
for (String fieldName : jsonObject.fieldNames()) {
JsonArray jsonArray = jsonObject.getJsonArray(fieldName);
Observable<JsonObject> observable = Observable
.fromIterable(jsonArray)
.map(JsonObject.class::cast);
System.out.println("fieldName = " + fieldName);
observable.subscribe(json -> System.out.println("json = " + json));
}

How to prevent format change of date in view after save in ASP MVC

After saving DateTime in controller, I pass it back to the View but when it's displayed in view the value became /Date(1545062400000)/.
I already checked in the controller while in process if the data was changed but it did not since I'm just passing the viewmodel in the view.
[HttpPost]
public ActionResult UpdateHeader(RecordViewModel recordViewModel)
{
var ResultMessage = "";
if (ModelState.IsValid)
{
Record record = (from c in context.Records
where c.RecordId == recordViewModel.RecordId
select c).FirstOrDefault();
if (record == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
record.Description = recordViewModel.Description;
record.Date = recordViewModel.Date;
record.Remarks = recordViewModel.Remarks;
try
{
context.SaveChanges();
ResultMessage = "Record successfully updated.";
}
catch (Exception ex)
{
ModelState.AddModelError("", ErrorHelper.GetInnerException(ex));
ResultMessage = "Error: " + ErrorHelper.GetInnerException(ex);
}
}
var result = new { Model = recordViewModel, ResultMessage = ResultMessage };
return Json(result, JsonRequestBehavior.AllowGet);
}
Angular
self.submitEdit = function () {
var updateRecordHeader = RecordServices.updateRecordHeader(self.header)
.then(function successCallback(response) {
self.header = response.data.Model;
self.header.ResultMessage = response.data.ResultMessage;
}, function errorCallback(response) { toastr.error(response.statusText); });
}
The /Date(1545062400000)/ is known as date ticks using UNIX timestamp format since RFC7519 "epoch" (January 01, 1970), which cannot be directly consumed as JS Date object without converting it first. The reason behind usage of the ticks is JSON format doesn't have specific representation for DateTime struct when serialized to plain strings (see this reference).
You can create a custom function to convert ticks into JS Date object:
function toJSDate(value) {
var regex = /Date\(([^)]+)\)/;
var results = regex.exec(value);
var date = new Date(parseFloat(results[1])); // or parseInt
return date;
}
Or even simpler without regex by picking numeric values directly like this:
function toJSDate(value) {
var date = new Date(parseFloat(value.substring(6))); // or parseInt
return date;
}
Then use that function for ticks-to-date conversion:
// example
var header = response.data.Model;
var dateObject = toJSDate(header.Date);
// assign date object afterwards
Note that you may need to create another object structure which resembles response.data.Model but using server-side Date property with JS date object.
As an alternative you may create a getter-only string property which uses ToString() to convert DateTime value into desired string representation, then use it inside JS.
Side note:
Avoid using viewmodel property name which exactly matches built-in JS function names & objects (i.e. Date) for clarity.
Related issues:
How do I format a Microsoft JSON date?
Converting .NET DateTime to JSON

JSON Response IBM BPM

In our environment we have to prepare the response call with a JSON format (tw.local.jsonResponse). I'm new to JSON, not sure how to parse the date with the following JSON format in IBM BPM. It could be a great help if anyone guide/suggest (by using the following data).
Success Response
Code: 200
Content:
{
“status” : “success”
“data” : {
“change_number” : [string],
“instance” : [string],
“customer” : [string],
“tasks” : [
{ “task_number” : [string],
“description” : [string],
“schedule_start” : [datetime],
“schedule_end” : [datetime]
},
{ /* another task */ }
]
}
}
I have experienced similar problem with json and dates in IBM BPM.
In your solution, you can get the external JavaScript file json.js.
You can use the following function to return your JSON string:
BPMJSON.convertTWToJSON(tw.local.MyObject, false)
The first thing you need to do is make BO with require Datatype with the same name of BO.
Then use the following code to convert twObject to JSON:-
function createJson(twObject){
var jsonString="";
if(typeof twObject =='object' && twObject!=null){
if(twObject.listLength>0){
jsonString+="[";
for (var j=0; j<twObject.listLength; j++){
if(typeof twObject[j]!='string')
jsonString+="{";
for (var property in twObject[j].propertyNames){
var name = twObject[j].propertyNames[property];
if(typeof twObject[j][name]=='object'){
if(Object.prototype.toString.call(twObject[j][name]).indexOf("TWDate")!="-1"){
jsonString+="\""+name+"\":\""+twObject[j][name].format("yyyy-MM-dd'T'HH:mm:ss'Z'")+"\",";
}else{
jsonString+="\""+name+"\":"+createJson(twObject[j][name]);
}
}
else{
jsonString+="\""+name+"\":\""+twObject[j][name]+"\",";
}
if(twObject[j].listLength>0)
{
for (var k=0;k<twObject[j].listLength;k++){
jsonString+="\""+ twObject[j][k]+"\",";
}
}
}
if(typeof twObject[j] == 'string'){
jsonString+="\""+twObject[j]+"\"";
}
if(typeof twObject[j]!='string')
jsonString+="}";
if(j!=twObject.listLength-1){
jsonString+=",";
}
} jsonString+="],";
}else{
try{
if(twObject.propertyNames.length>0){
jsonString+="{";
for(var property in twObject.propertyNames){
var name = twObject.propertyNames[property];
if(typeof twObject[name]=='object'){
if(Object.prototype.toString.call(twObject[name]).indexOf("TWDate")!="-1"){
jsonString+="\""+name+"\":\""+twObject[name].format("yyyy-MM-dd'T'HH:mm:ss'Z'")+"\",";
}else{
jsonString+="\""+name+"\":"+createJson(twObject[name]);
}
}else{
jsonString+="\""+name+"\":\""+twObject[name]+"\",";
}
}
jsonString+="},"; }
else{
return "{},";
}}catch(e){
return "{},";
}
}
}
else if(typeof twObject =='object' && twObject==null){
return "{},";
}
return jsonString;
}
Source Code:http://www.ibpmcoding.com.
This is what worked in BPM 8.6 for a Rest Token:
tw.local.authToken = JSON.parse(tw.system.invokeREST(request).content).access_token;
Explained part by part:
tw.system.invokeREST(request)
Invoke the REST client to make a call.
tw.system.invokeREST(request).content
Contains the response as a jsonstring.
JSON.parse(tw.system.invokeREST(request).content).access_token
Parses it back to a json object and extract the attribute access_token as a string.
Humm.. I see why you have issue. Let me make it clear.
JSON Dates are not dates – they are Strings!!
So there is no fix format of date within JSON but we are lucky in case of IBM BPM.
String representation of date are in format of UTC time (indicated by the Z) in case of IBM BPM, for example
"2020-09-24T18:04:41.306Z"
You can convert this date string to JS Date on any browser using any date function for example
new Date("2020-09-24T18:04:41.306Z")
On server side JS you can use the same trick, converting sting date to JS date.

How do I pull out the JSON field I want using Jackson TreeNode and JsonNode?

I'm a little stumped why I can't pull the "Type" field out of my JSON stream to make a decision. It seems like this should be so easy.
I have the following JSON that I have as input:
[
{
"Institution":"ABC",
"Facility":"XYZ",
"Make":"Sunrise",
"Model":"Admission",
"SerialNumber":"",
"Revision":"1",
"Type":"ABC_Admission",
"ArchiveData":"<CSV file contents>"
}
]
In my Java I have a try-catch block with a JsonHolder class that implements Serializable to hold the JSON. Here's the Java I currently have:
try {
// Parse and split the input
JsonHolder data = JsonHolder.getField("text", input);
DataExtractor.LOG.info("JsonHolder data= " + data);
TreeNode node = data.getTreeNode();
DataExtractor.LOG.info("node size= " + node.size());
node = node.path("Type");
JsonNode json = (JsonNode) node;
DataExtractor.LOG.info("json= " + json.asText());
// code to decide what to do based on Type found
if (json.asText().equals("ABC_Admission")) {
// do one thing
} else {
// do something else
}
} catch (IOException iox) {
DataExtractor.LOG.error("Error extracting data", iox);
this.collector.fail(input);
}
When I run my code I get the following output (NOTE: I changed my package name where the class is to just for this output display)
25741 [Thread-91-DataExtractor] INFO <proprietary package name>.DataExtractor - JsonHolder data= [
{
"Institution":"ABC",
"Facility":"XYZ",
"Make":"Sunrise",
"Model":"Admission",
"SerialNumber":"",
"Revision":"1",
"Type":"ABC_Admission",
"ArchiveData":"<CSV file contents>"
}
]
25741 [Thread-91-DataExtractor] INFO <proprietary package name>.DataExtractor - node size= 1
25741 [Thread-91-DataExtractor] INFO <proprietary package name>.DataExtractor - json=
As you can see I don't get anything out. I just want to extract the value of the field "Type", so I was expecting to get the value "ABC_Admission" in this case. I would have thought the node path would separate out just that field from the rest of the JSON tree.
What am I doing wrong?
After consulting with another developer I found out the issue is my JSON is inside an array. So, I need to iterate over that array and then pull out the Type field from the object.
The updated code to resolve this is below:
try {
// Parse and split the input
JsonHolder data = JsonHolder.getField("text", input);
DataExtractor.LOG.info("JsonHolder data= " + data);
TreeNode node = data.getTreeNode();
String type = null;
// if this is an array of objects, iterate through the array
// to get the object, and reference the field we want
if (node.isArray()){
ArrayNode ary = (ArrayNode) node;
for (int i = 0; i < ary.size(); ++i) {
JsonNode obj = ary.get(i);
if (obj.has("Type")) {
type = obj.path("Type").asText();
break;
}
}
}
if (type == null) {
// Do something with failure??
}
DataExtractor.LOG.info("json= " + type);
if (type.equals("ABC_Admission")) {
// do one thing
else {
// do something else
}
} catch (IOException iox) {
DataExtractor.LOG.error("Error extracting data", iox);
this.collector.fail(input);
}

use ko.utils.arrayfilter to return collection based on value of inner collection

I am using knockout and want to use arrayFilter to return array of objects where a property "modified" inside of another array has value of true.
i.e.
my json object looks like
Family tree
Family{
LastName=Smith
Children{
Name=bob,
Modified=false},
{
Name=tom, Modified=true}
}
Family{
LastName=Jones
Children{
Name=bruno,
Modified=false},
{
Name=mary, Modified=false}
}
The result of the array filter would be (as follows) becuase child tom has modified =true
FamilyTree
Family{
LastName=Smith
Children{
Name=bob,
Modified=false},
{
Name=tom, Modified=true}
}
is this possible?
I think the solution that #pax162 supplied probably answers your question. However, there is the question of usage. The proposed solution is going to perform nested iterations. If you are only expecting to be processing the data once (as opposed to driving some rich client views), this is the approach to take. On the other hand, if you are binding this data to a view, you might consider another more KO-like approach. Here's what I have in mind:
var family = function(data){
var self = {
LastName :ko.observable(data.LastName),
Children : ko.observableArray( data.Children || [])
};
family.hasModifiedChildren = ko.computed(function() {
return ko.utils.arrayFirst(this.Children(),
function(child) {
return child.Modified === true;
}) !== null;
}, family);
return self;
}
Rather than using JSON data, create observable JS objects as such:
var families = return ko.utils.arrayMap(familiesJson, family);
// or, if you need an observable:
families = ko.observableArray(ko.utils.arrayMap(familiesJson, family));
Finally, get your list of families with modified children like this:
var familiesWithModifiedChildren = ko.computed(function() {
return ko.utils.arrayFilter(families, function(fam) {
return fam.hasModifiedChildren();
});
});
If you are building a live-update page, you'll want to go with this style of view model. This will allow Knockout to utilize its observer optimizations rather than building a new array every time the function is evaluated. Hope this helps!
If you want to get only families with at least one modified child, you can do this (http://jsfiddle.net/MAyNn/3/) . The json was not valid, changed it a bit.
var families = [
{
LastName :"Smith",
Children : [{
Name:"bob",
Modified:false},
{
Name:"tom", Modified :true}
]
},
{
LastName :"Jones",
Children : [{
Name:"bruno",
Modified:false},
{
Name:"mary", Modified :false}
]
}
];
var filteredFamilies = ko.utils.arrayFilter(families, function(family){
var hasModified = false;
var first = ko.utils.arrayFirst(family.Children, function(child){
return child.Modified;
})
if (first) {
hasModified = true;
}
return hasModified;
})
console.log(families);
console.log(filteredFamilies);