Generate friendly JSON from XML in NodeJS - node.js

Currently, I'm receiving an API request that has the crazy structure to the data, I'm attempting to parse the XML part of the response to an array/JSON so I can handle it.
Here's the exact request I am receiving:
{
username: 'test',
apiaccesskey: 'aa7a8157-3c17-4b63-806f-7aeff42ae21f',
action: 'placeimeiorder',
requestformat: 'JSON',
parameters:
'<PARAMETERS><CUSTOMFIELD>bnVsbA==</CUSTOMFIELD><ID>1</ID><SERVICEID>1</SERVICEID><IMEI>12345678910</IMEI><QNT>1</QNT><SERVER>0</SERVER><MODELID></MODELID><PROVIDERID></PROVIDERID><NETWORK></NETWORK><PIN></PIN><KBH></KBH><MEP></MEP><PRD></PRD><TYPE></TYPE><LOCKS></LOCKS><REFERENCE></REFERENCE><SN></SN><SECRO></SECRO></PARAMETERS>\n',
version: '7.2'
}
I've tried parsing using this library (xml2js) but it's generating a result like this:
let parseresult = await parser.parseStringPromise(req.body.parameters);
console.log(parseresult);
{ PARAMETERS:
{ CUSTOMFIELD: [ 'bnVsbA==' ],
ID: [ '1' ],
SERVICEID: [ '1' ],
IMEI: [ '12345678910' ],
QNT: [ '1' ],
SERVER: [ '0' ],
MODELID: [ '' ],
PROVIDERID: [ '' ],
NETWORK: [ '' ],
PIN: [ '' ],
KBH: [ '' ],
MEP: [ '' ],
PRD: [ '' ],
TYPE: [ '' ],
LOCKS: [ '' ],
REFERENCE: [ '' ],
SN: [ '' ],
SECRO: [ '' ] } }
which is far from ideal when trying to handle, how could I change it so I could simply access individual key/values like parseresult.IMEI or parseresult.CUSTOMFIELD

Should just be a setting.
Code:
const xml2js = require('xml2js');
const parser = new xml2js.Parser({ explicitArray: false });
const xml = "<PARAMETERS><CUSTOMFIELD>bnVsbA==</CUSTOMFIELD><ID>1</ID><SERVICEID>1</SERVICEID><IMEI>12345678910</IMEI><QNT>1</QNT><SERVER>0</SERVER><MODELID></MODELID><PROVIDERID></PROVIDERID><NETWORK></NETWORK><PIN></PIN><KBH></KBH><MEP></MEP><PRD></PRD><TYPE></TYPE><LOCKS></LOCKS><REFERENCE></REFERENCE><SN></SN><SECRO></SECRO></PARAMETERS>\n";
parser.parseString(xml, (err, result) => {
console.dir(result);
});
Reference: https://github.com/Leonidas-from-XIV/node-xml2js#options
Output:
{
PARAMETERS: {
CUSTOMFIELD: 'bnVsbA==',
ID: '1',
SERVICEID: '1',
IMEI: '12345678910',
QNT: '1',
SERVER: '0',
MODELID: '',
PROVIDERID: '',
NETWORK: '',
PIN: '',
KBH: '',
MEP: '',
PRD: '',
TYPE: '',
LOCKS: '',
REFERENCE: '',
SN: '',
SECRO: ''
}
}
Alternative:
Using the async/await like you have above:
const xml2js = require('xml2js');
(async () => {
const parser = new xml2js.Parser({ explicitArray: false });
const xml = "<PARAMETERS><CUSTOMFIELD>bnVsbA==</CUSTOMFIELD><ID>1</ID><SERVICEID>1</SERVICEID><IMEI>12345678910</IMEI><QNT>1</QNT><SERVER>0</SERVER><MODELID></MODELID><PROVIDERID></PROVIDERID><NETWORK></NETWORK><PIN></PIN><KBH></KBH><MEP></MEP><PRD></PRD><TYPE></TYPE><LOCKS></LOCKS><REFERENCE></REFERENCE><SN></SN><SECRO></SECRO></PARAMETERS>\n";
try {
console.log(await parser.parseStringPromise(xml))
} catch (error) {
console.log('ERROR', error);
}
})();

If you want complete control over the conversion, try saxon-js (released on Node.js a couple of weeks ago, available from npm).
For example you could do it in XPath 3.1 like this:
const SaxonJS = require("saxon-js");
SaxonJS.getResource({text:xml, type:"xml"})
.then(doc => {
SaxonJS.serialize(
SaxonJS.XPath.evaluate(
"map:merge(/PARAMETERS/* ! map{name(): string()})", doc),
{method:"json", indent:true}))});
You could extend this, for example to select which fields of the XML to include in the result.
Or for even more flexibility, you could do it in XSLT3.
(Not tested.)

you can also use camaro, a xpath-powered template to transform the value. it looks like this
const { transform } = require('camaro')
const data = {
username: 'test',
apiaccesskey: 'aa7a8157-3c17-4b63-806f-7aeff42ae21f',
action: 'placeimeiorder',
requestformat: 'JSON',
parameters:
'<PARAMETERS><CUSTOMFIELD>bnVsbA==</CUSTOMFIELD><ID>1</ID><SERVICEID>1</SERVICEID><IMEI>12345678910</IMEI><QNT>1</QNT><SERVER>0</SERVER><MODELID></MODELID><PROVIDERID></PROVIDERID><NETWORK></NETWORK><PIN></PIN><KBH></KBH><MEP></MEP><PRD></PRD><TYPE></TYPE><LOCKS></LOCKS><REFERENCE></REFERENCE><SN></SN><SECRO></SECRO></PARAMETERS>\n',
version: '7.2',
}
async function main() {
console.log(await transform(data.parameters, {
customerField: 'PARAMETERS/CUSTOMFIELD',
customerId: 'PARAMETERS/ID',
serviceId: 'PARAMETERS/SERVICEID',
}));
}
main()
output
{ customerField: 'bnVsbA==', customerId: '1', serviceId: '1' }
If you want more fields, you can just edit the template

Related

Difficulty using csvtojson to create nested JSON structure from csv

There's a feature in the csvtojson package where you can create a nested JSON object from a CSV file permitting you configure the headers correctly. However, I'm having difficulty applying the schema shown in the above link for my CSV file.
My current CSV structure is this:
And the JSON structure I'm trying to create should look something like this:
{
Name: 'Bedminster Twp East',
Contests: [
{
Name: 'JUSTICE OF THE SUPREME COURT',
Candidates: [
{
Name: 'Maria McLaughlin',
Votes: 511
},
{
Name: 'Kevin Brobson',
Votes: 857
},
{
Name: 'Write-In',
Votes: 1
},
]
},
{
Name: 'JUDGE OF THE SUPERIOR COURT',
Candidates: [
{
Name: 'Timika Lane',
Votes: 494
},
{
Name: 'Megan Sullivan',
Votes: 870
},
{
Name: 'Write-In',
Votes: 1
},
]
}
...
],
Turnout: '45.77%'
},
...
This is the existing code I have:
const csv = require('csvtojson');
const axios = require('axios');
axios({
method: 'get',
url: 'URL'
}).then(function(response) {
let x = response.data.split('\n');
x.splice(0, 2);
let newX = x.join('\n');
csv({
noheader: false,
headers: ['Precinct.Name', 'Precinct.Contests.Name', 'Precinct.Contests.Name.Candidates.Name', 'Precinct.Contests.Name.Candidates.Votes', 'Precinct.Turnout']
}).fromString(newX).then((csvRow) => {
console.log(csvRow);
});
});
Which is unfortunately creating the following JSON structure:
[
{
Precinct: {
Name: 'Bedminster Twp East',
Contests: [Object],
Turnout: '47.89%'
}
},
{
Precinct: {
Name: 'Bedminster Twp East',
Contests: [Object],
Turnout: '47.89%'
}
},
{
Precinct: {
Name: 'Bedminster Twp East',
Contests: [Object],
Turnout: '47.89%'
}
},
{
Precinct: {
Name: 'Bedminster Twp East',
Contests: [Object],
Turnout: '47.89%'
}
},
... 19841 more items
I don't know exactly what is in the "Contests" object, but considering that the number of objects is equal to the number of rows in the existing CSV file, I believe there is something wrong with my header grouping. I can't tell if I'm severely misreading the documentation linked earlier or if it's not clear enough. Thanks for any assistance.
EDIT: I'm splitting and joining because the first two rows are metadata that says "UNOFFICIAL RESULTS" and "2022", which I don't want being read in.
try this headers configuration:
headers: ['Name', 'Contests[0].Name', 'Contests[0].Candidates[0].Name', 'Contests[0].Candidates[0].Votes', 'Turnout']

Add information to a spreadsheet from the Google API

I have a Typescript and Node project in which I am trying to insert the information I get from the database into the spreadsheet using the Google API V4
https://sheets.googleapis.com/v4/spreadsheets/{spreadsheetId}:batchUpdate
This is the JSON object that I get from the database:
let sheetData = [
{
"country":null,
"age":25,
"fileName":"testName1"
},
{
"country":"Spain",
"age":null,
"fileName":"testName2"
}
]
I transform it with papaparse:
const papa = require("papaparse")
let result = papa.unparse(sheetData, {
header: false,
delimiter: ';',
encoding: 'UTF-8',
})
console.log(result)
This is what I get:
;25;testName1
Spain;;testName2
This is the xml that I use from the API to add the information:
{
"requests": [
{
"pasteData": {
"coordinate": {
"sheetId": 123,
"rowIndex": 2,
"columnIndex": 1
},
"delimiter": ";",
"type": "PASTE_VALUES",
"data": ";25;testName1Spain;;testName2"
}
}
]
}
I attach a screenshot with the result of the sheet:
My problem: All the information is put in the same row, how do I have to modify the array to include line breaks and be identified by the API?
This is the JSON that works from the API by adding \n:
{
"requests": [
{
"pasteData": {
"coordinate": {
"sheetId": 123,
"rowIndex": 2,
"columnIndex": 1
},
"delimiter": ";",
"type": "PASTE_VALUES",
"data": ";25;testName1\nSpain;;testName2"
}
}
]
}
This is the result I want to achieve, but I don't know how to treat the JSON with the information I get:
I thought that in your script, how about the following sample script?
Sample script:
const sheets = google.sheets({ version: "v4", auth }); // Please use your authorization script.
let sheetData = [
{
country: null,
age: 25,
fileName: "testName1",
},
{
country: "Spain",
age: null,
fileName: "testName2",
},
];
let result = papa.unparse(sheetData, {
header: false,
delimiter: ";",
encoding: "UTF-8",
});
console.log(result);
const requests = {
requests: [
{
pasteData: {
coordinate: {
sheetId: 123, // Please set your sheet ID.
rowIndex: 2,
columnIndex: 1,
},
delimiter: ";",
type: "PASTE_VALUES",
data: result,
},
},
],
};
sheets.spreadsheets.batchUpdate(
{
spreadsheetId: "###", // Please set your Spreadsheet ID.
resource: requests,
},
(err, result) => {
if (err) {
console.log(err);
return;
}
console.log(result.data);
}
);
In this modification, your value of result is used as the data of pasteData request.
When I tested this script, I confirmed that your expected result can be obtained.

how to get the particular value from the response array received after wallet creation in bitgo Js

This is my array and want to get values from it:
{ wallet:
Wallet {
bitgo:
BitGo {
_baseUrl: 'https://test.bitgo.com',
env: 'test',
_baseApiUrl: 'https://test.bitgo.com/api/v1',
del: [Function] },
baseCoin:
BaseCoin {
network: [Object],
coinKeychains: [Keychains] },
_wallet:
{ id: '5b055bae749a9ba207410c65ff58c325',
users: [Array],
coin: 'tltc',
label: 'My Test Wallet',
m: 2,
n: 3,
pendingApprovals: [] } },
userKeychain:
{ id: '47i3ygdhfhdhjfj84378r'
users: [ '3w65gsdhfgshg93w2r2839'],
pub: 'zsnadfsheg94t854tidghfhdhgdhh kladjfghgdhfhdhfghdhhfghgh',
ethAddress: '0xzxder4tewre79618eceret3a2eabf6c8',
encryptedPrv: '{}',
prv: ' },
backupKeychain:
{ id: '54idhjfhdj9a9ba207410c505912c1b1',
users: [ '90jdfjgbja7007sdjbgjffc7a5065006' ],
pub: '',
ethAddress: '0x753ce0sdfvsdsgdf8baef8sdfesdfssfs2bdd8cb',
prv: '',
source: 'backup' },
bitgoKeychain:
{ id: '5b055bad39230ccc07814e0589388100',
users: [ '5ac1fd5563fa7007d5a17fc7a5065006' ],
pub: '',
ethAddress: '0xbfdgfdgdfdgfhfgtr6756ghfghfg719320fcc7e',
isBitGo: true },
}
// here want to get userKeychain, backupKeychain and bitgoKeychainPlease help how to fetch the this value. Is there any function to access this values or need any parsing method in bitgo Js.
You can get it using like : wallet.wallet._wallet.id
This will give you the wallet id.To get the userKeychain value use like wallet.userKeychain

Not Getting Search value in Sencha Touch using searchfield

I want to display predictive text in search field, value for predictive text which comes from server. Here is my code so far:
View:
Ext.define('MyApp.view.AutoSearch', {
extend: 'Ext.dataview.List',
alias : 'widget.mainPanel',
config: {
store : 'AutoSearchStore',
itemTpl: '<div class="myWord">'+
'<div>Word is --<b>{name}</b>--- after search!!!</div>' +
'</div>',
emptyText: '<div class="myWord">No Matching Words</div>',
items: [
{
xtype: 'toolbar',
docked: 'top',
items: [
{
xtype: 'searchfield',
placeHolder: 'Search...',
itemId: 'searchBox'
}
]
}
]
}
});
Store:
Ext.define('MyApp.store.AutoSearchStore',{
extend: 'Ext.data.Store',
config:
{
model: 'MyApp.model.AutoSearchModel',
autoLoad:true,
id:'Contacts',
proxy:
{
type: 'ajax',
url: 'http://alucio.com.np/trunk/dev/sillydic/admin/api/word/categories/SDSILLYTOKEN/650773253e7f157a93c53d47a866204dedc7c363',
reader:
{
rootProperty:''
}
}
}
});
Model:
Ext.define('MyApp.model.AutoSearchModel', {
extend: 'Ext.data.Model',
requires: ['MyApp.model.AutoSearchModelMenu'],
config: {
fields: [
{name:'data', mapping: 'data'},
{name: 'name'},
],
},
});
and
Ext.define('MyApp.model.AutoSearchModelMenu', {
extend: 'Ext.data.Model',
config: {
fields: [
'name',
],
belongsTo: "MyApp.model.AutoSearchModel"
}
});
Controller:
Ext.define('MyApp.controller.SearchAutoComplete', {
extend : 'Ext.app.Controller',
config: {
profile: Ext.os.deviceType.toLowerCase(),
stores : ['MyApp.store.AutoSearchStore'],
models : ['MyApp.model.AutoSearchModel'],
refs: {
myContainer: 'mainPanel'
},
control: {
'mainPanel': {
activate: 'onActivate'
},
'mainPanel searchfield[itemId=searchBox]' : {
clearicontap : 'onClearSearch',
keyup: 'onSearchKeyUp'
}
}
},
onActivate: function() {
console.log('Main container is active--Search');
},
onSearchKeyUp: function(searchField) {
queryString = searchField.getValue();
console.log(this,'Please search by: ' + queryString);
var store = Ext.getStore('AutoSearchStore');
store.clearFilter();
if(queryString){
var thisRegEx = new RegExp(queryString, "i");
store.filterBy(function(record) {
if (thisRegEx.test(record.get('name'))) {
return true;
};
return false;
});
}
},
onClearSearch: function() {
console.log('Clear icon is tapped');
var store = Ext.getStore('AutoSearchStore');
store.clearFilter();
},
init: function() {
console.log('Controller initialized for SearchAutoComplete');
}
});
Json Data Looks Like:
"data":[
{
"name":"paint",
"author":"admin",
"word_id":"1",
"category":"Business",
"is_favourite":"yesStar"
},
{
"name":"abacus",
"author":"admin",
"word_id":"2",
"category":"Education",
"is_favourite":"yesStar"
},
{
"name":"abate",
"author":"admin",
"word_id":"3",
"category":"Education",
"is_favourite":"noStar"
},
{
"name":"testing adsf",
"author":"admin",
"word_id":"7",
"category":"Education",
"is_favourite":"noStar"
},
{
"name":"sprite",
"author":"admin",
"word_id":"6",
"category":"Business",
"is_favourite":"noStar"
},
{
"name":"newword",
"author":"admin",
"word_id":"8",
"category":"Architecture",
"is_favourite":"noStar"
}
]
})
If I type "A", then it displays No Matching Words, but I have words from "A" on json coming from server. How to solve this problem?
Any idea!
Code Sources Link
I don't know why you are using two models but just one thing you need to specify in AutoSearchStore :
reader:
{
rootProperty:'data'
}
instead of
reader:
{
rootProperty:''
}
to get the expected results in the list.
Hope this will be helpful :)

Inline array store data in ExtJS4?

I'm unable to load inline array data into a store. In particular, this fails.
Can someone explain why? I even tried adding a memory proxy with an array reader and still no dice.
Ext.define('MyApp.store.ComboboxState', {
extend: 'Ext.data.Store',
constructor: function(cfg) {
var me = this;
cfg = cfg || {};
me.callParent([Ext.apply({
autoLoad: true,
storeId: 'ComboboxState',
data: [
[
'AL',
'Alabama'
]
]
,fields: [
{
name: 'state'
},
{
name: 'name'
}
]
}, cfg)]);
}
});
Still doesn't work with this memory proxy/array reader:
proxy: {
type: 'memory',
reader: {
type: 'array'
}
}
Just extend from ArrayStore, like this:
Ext.define('MyApp.store.ComboboxState', {
extend: 'Ext.data.ArrayStore',
constructor: function(cfg) {
var me = this;
cfg = cfg || {};
me.callParent([Ext.apply({
autoLoad: true,
storeId: 'ComboboxState',
data: [
[
'AL',
'Alabama'
]
]
,fields: ['state', 'name' ]
}, cfg)]);
}
});
JsFiddle to try: http://jsfiddle.net/voidmain/hKwbJ/

Resources