Object values are becoming null instantly - javascript

I have the following functions with two console.log() calls.
get = function(path, obj){
for(var i = 0, path = path.split(/[\[\]\.]/), len = path.length; i < len; i++){
if(path[i]){
console.log(obj);
obj = obj[path[i]];
console.log(obj);
if(typeof obj === 'undefined'){
return '';
}
}
}
return obj;
};
set = function(path, obj, dta){
for(var i = 0, path = path.split(/[\[\]\.]/), len = path.length; i < len; i++){
if(path[i]){
obj = obj[path[i]];
if(typeof obj === 'undefined'){
return false;
}
}
}
obj = dta;
return true;
};
I then call them like this:
var data = {
user: {
secret: null,
accessToken: null
},
baseurl: 'http://api.example.com'
};
set('user', data, {/* new object data */});
get('user', data);
When the first console.log() is called, the object looks like this:
{
baseurl: "http://api.example.com",
user: {
accessToken: "12324",
secret: "123413421341342134"
}
}
Then when the second console.log() is called, the secret and accessToken look like this:
{
secret: null, accessToken: null
}
What is causing these to become null?

Your set() function does nothing. Assigning an object member to a variable, then setting that variable, doesn't affect the original object member.
You can keep track of the parent of the property-in-question, and use that to do your assignment:
set = function(path, obj, dta){
var parent = obj;
var selector = null;
for(var i = 0, path = path.split(/[\[\]\.]/), len = path.length; i < len; i++){
if(path[i]){
parent = obj;
selector = path[i];
obj = obj[path[i]];
if(typeof obj === 'undefined'){
return false;
}
}
}
if (parent && selector)
{
parent[selector] = dta;
return true;
}
return false;
};
var get = function(path, obj) {
for (var i = 0, path = path.split(/[\[\]\.]/), len = path.length; i < len; i++) {
if (path[i]) {
console.log(obj);
obj = obj[path[i]];
console.log(obj);
if (typeof obj === 'undefined') {
return '';
}
} // x
}
return obj;
};
var set = function(path, obj, dta) {
var parent = obj;
var selector = null;
for (var i = 0, path = path.split(/[\[\]\.]/), len = path.length; i < len; i++) {
if (path[i]) {
parent = obj;
selector = path[i];
obj = obj[path[i]];
if (typeof obj === 'undefined') {
return false;
}
}
}
if (parent && selector)
parent[selector] = dta;
return true;
};
var data = {
user: {
secret: null,
accessToken: null
},
baseurl: 'http://api.example.com'
};
set('user', data, {
secret: 1,
accessToken: 2
});
get('user', data);

Related

convert html code to Json array using JavaScript function

I use this function to convert html element to Json file:
function converter(dom) {
if (dom.nodeType === Node.TEXT_NODE) {
return dom.nodeValue;
}
if (dom.nodeType === Node.DOCUMENT_NODE) {
dom = dom.documentElement;
}
const obj = {};
obj.nodeType = dom.nodeType;
if (dom.nodeType === Node.ELEMENT_NODE) {
obj.tagName = dom.tagName;
obj.attributes = []; // Array.from(obj.attributes) gives us a lot of things we don't want
for (let i = 0, len = dom.attributes.length; i < len; ++i) {
const attr = dom.attributes[i];
obj.attributes.push({name: attr.name, value: attr.value});
}
obj.children = [];
for (let child = dom.firstChild; child; child = child.nextSibling) {
obj.children.push(converter(child));
}
} else {
obj.nodeValue = dom.nodeValue;
}
return obj;
}
const jsonn = JSON.stringify(converter(document.getElementById("examplee")), null, 4);
var data = JSON.parse(jsonn);
console.log(data);
<div id='examplee'>text</div>
Now I want to make it accept HTML code in the conveter intstead of DOM
make it work like this:
function converter(dom) {
if (dom.nodeType === Node.TEXT_NODE) {
return dom.nodeValue;
}
if (dom.nodeType === Node.DOCUMENT_NODE) {
dom = dom.documentElement;
}
const obj = {};
obj.nodeType = dom.nodeType;
if (dom.nodeType === Node.ELEMENT_NODE) {
obj.tagName = dom.tagName;
obj.attributes = []; // Array.from(obj.attributes) gives us a lot of things we don't want
for (let i = 0, len = dom.attributes.length; i < len; ++i) {
const attr = dom.attributes[i];
obj.attributes.push({name: attr.name, value: attr.value});
}
obj.children = [];
for (let child = dom.firstChild; child; child = child.nextSibling) {
obj.children.push(converter(child));
}
} else {
obj.nodeValue = dom.nodeValue;
}
return obj;
}
const jsonn = JSON.stringify(converter("<div>12345</div>"), null, 4);
var data = JSON.parse(jsonn);
console.log(data);
But it returns empty tags. I want it to return the json when I put in the converter.
The problem is it accepts only the document.getElementById("examplee") and not accept the code like the snippet above
Not sure if this is what you're after, but in the first example you're using an HTML element as an argument, whereas in the second example you're using a string as an argument. For that, I've added the following to the beginning of your function:
if (typeof dom === 'string') {
let tmp = document.createElement('template');
tmp.innerHTML = dom;
dom = tmp.content.childNodes[0]
}
function converter(dom) {
if (typeof dom === 'string') {
let tmp = document.createElement('template');
tmp.innerHTML = dom;
dom = tmp.content.childNodes[0]
}
if (dom.nodeType === Node.TEXT_NODE) {
return dom.nodeValue;
}
if (dom.nodeType === Node.DOCUMENT_NODE) {
dom = dom.documentElement;
}
const obj = {};
obj.nodeType = dom.nodeType;
if (dom.nodeType === Node.ELEMENT_NODE) {
obj.tagName = dom.tagName;
obj.attributes = []; // Array.from(obj.attributes) gives us a lot of things we don't want
for (let i = 0, len = dom.attributes.length; i < len; ++i) {
const attr = dom.attributes[i];
obj.attributes.push({
name: attr.name,
value: attr.value
});
}
obj.children = [];
for (let child = dom.firstChild; child; child = child.nextSibling) {
obj.children.push(converter(child));
}
} else {
obj.nodeValue = dom.nodeValue;
}
return obj;
}
const jsonn = JSON.stringify(converter("<div>12345</div>"), null, 4);
var data = JSON.parse(jsonn);
console.log(data);

convert xml to json in Javascript

I have the following javascript function (which I got from Stack Overflow) which converts XML to JSON:
function xmlToJson(xml) {
try {
var obj = {};
if (xml.nodeType == 1) {
if (xml.attributes.length > 0) {
for (var j = 0; j < xml.attributes.length; j++) {
var attribute = xml.attributes.item(j);
obj[attribute.nodeName] = attribute.nodeValue;
}
}
} else if (xml.nodeType == 3) {
obj = xml.nodeValue;
}
if (xml.hasChildNodes()) {
for (var i = 0; i < xml.childNodes.length; i++) {
var item = xml.childNodes.item(i);
var nodeName = item.nodeName;
if (typeof (obj[nodeName]) == "undefined") {
obj[nodeName] = xmlToJson(item);
} else {
if (typeof (obj[nodeName].push) == "undefined") {
var old = obj[nodeName];
obj[nodeName] = [];
obj[nodeName].push(old);
}
obj[nodeName].push(xmlToJson(item));
}
}
}
console.log(JSON.stringify(obj));
return obj;
} catch (e) {
alert(e.message);
}
}
What I want is to return it as an array ([]) when a xml node has at-least single child node and it has a parent node also. In this code it returns map ({}) if xml node has single child node but it is fine with multiple child nodes.
For example, I'd like the XML
<pnode attr1="abc">
<cnode attr2="xyz"></cnode>
</pnode>
to be transformed into the JSON
{
"pnode": {
"attr1": "abc"
},
"cnode": [
{"attr2": "xyz"}
]
}
With the clarification about what you want to achieve, here is an algorithm.
I'll leave my other answer up because I still think the wisest choice is not to play with the structure
function flattenNodes(node, isChild) {
var obj = {}, obj2, i, key, attributes = {};
if (node.attributes && node.attributes.length)
for (i = 0; i < node.attributes.length; ++i)
attributes[node.attributes[i].nodeName] = node.attributes[i].nodeValue;
if (!isChild)
obj[node.nodeName] = attributes;
else {
if (!obj.hasOwnProperty(node.nodeName))
obj[node.nodeName] = [];
else if (!(obj[node.nodeName] instanceof Array))
obj[node.nodeName] = [obj[node.nodeName]];
obj[node.nodeName].push(attributes);
}
attributes = null; // free
if (node.childNodes && node.childNodes.length)
for (i = 0; i < node.childNodes.length; ++i) {
if (node.childNodes[i].nodeType === 3) continue; // skip text node
obj2 = flattenNodes(node.childNodes[i], 1); // recurse
for (key in obj2) // merge
if (obj2.hasOwnProperty(key))
if (!obj.hasOwnProperty(key)) {
obj[key] = obj2[key];
} else {
if (!(obj[key] instanceof Array))
obj[key] = [obj[key]];
obj[key] = obj[key].concat(obj2[key]);
}
}
return obj;
}
Example usage on Node root_node
var root_node;
root_node = new DOMParser().parseFromString(
'<pnode attr1="abc"><cnode attr2="xyz"></cnode></pnode>',
'text/xml'
).documentElement;
var o = flattenNodes(root_node); // create
JSON.stringify(o); // to JSON
// {"pnode":{"attr1":"abc"},"cnode":[{"attr2":"xyz"}]}
If you have XML of the form <foo bar="baz"><foo hello="world"></foo></foo>, the first iteration will cause {foo: {bar: "baz"}}, then the second encounter will modify this to the array form of {foo: [{bar: "baz"}, {hello: "world"}]}
I would form the object representing the XML differently;
Integer nodeType
String nodeName
String nodeValue
Array childNodes
Object attributes
Now you can have the same form independent of number of child nodes/etc
function nodeToObject(node) {
var obj = {}, i;
obj.nodeType = node.nodeType;
obj.nodeName = node.nodeName;
obj.nodeValue = node.nodeValue;
obj.childNodes = [];
obj.attributes = {};
if (node.childNodes && node.childNodes.length)
for (i = 0; i < node.childNodes.length; ++i)
obj.childNodes.push(nodeToObject(node.childNodes[i]));
if (node.attributes && node.attributes.length)
for (i = 0; i < node.attributes.length; ++i)
obj.attributes[node.attributes[i].nodeName] = node.attributes[i].nodeValue;
return obj;
}
And then to transform root_node to JSON,
JSON.stringify(nodeToObject(root_node));
Going in the opposite direction is also possible in JavaScript, with some minor logic based upon nodeType to choose the creation method.

Easy way to get multi-level javascript object property

I always need to deal with multi-level js objects where existence of properties are not certain:
try { value1 = obj.a.b.c; } catch(e) { value1 = 1; }
try { value2 = obj.d.e.f; } catch(e) { value2 = 2; }
......
Is there an easier way or a generic function (e.g. ifnull(obj.d.e.f, 2) ) that does not require a lot of try catches?
var value1 = (obj.a && obj.a.b && obj.a.b.c) || 1;
http://jsfiddle.net/DerekL/UfJEQ/
Or use this:
function ifNull(obj, key, defVal){
var keys = key.split("."), value;
for(var i = 0; i < keys.length; i++){
if(typeof obj[keys[i]] !== "undefined"){
value = obj = obj[keys[i]];
}else{
return defVal;
}
}
return value;
}
var value1 = ifNull(obj, "a.b.c", 1);
You could always create a helper function.
function isUndefined(root, path, defaultVal) {
var parts = path.split('.'),
i = 0,
len = parts.length,
o = root || {}, v;
while ((typeof (v = o[parts[i]]) === 'object', o = v) && ++i < len);
return (typeof v === 'undefined' || i !== len)? defaultVal: v;
}
var obj = {a: { b: { test: 'test' }}}, v;
v = isUndefined(obj, 'a.b.test', 1); //test
v = isUndefined(obj, 'a.test', 1); //1
Using lodash you can do this easily**(node exists and empty check for that node)**..
var lodash = require('lodash-contrib');
function invalidateRequest(obj, param) {
var valid = true;
param.forEach(function(val) {
if(!lodash.hasPath(obj, val)) {
valid = false;
} else {
if(lodash.getPath(obj, val) == null || lodash.getPath(obj, val) == undefined || lodash.getPath(obj, val) == '') {
valid = false;
}
}
});
return valid;
}
Usage:
leaveDetails = {
"startDay": 1414998000000,
"endDay": 1415084400000,
"test": { "test1" : 1234 }
};
var validate;
validate = invalidateRequest(leaveDetails, ['startDay', 'endDay', 'test.test1']);
it will return boolean.

Search object with namespace / key

I'm trying to write a function that can look up a namespace and value in a JavaScript object and return the key.
Image this data:
var o = {
map: {
lat : -33.86749,
lng : 151.20699,
zoom : 12
},
filters : {
animals : {
dogs: {
myDog : 'fido'
}
}
}
};
function get(namespace, key){
//TODO
}
get('filters.animals.dogs', 'myDog')
How would you build a function that does this dynamically - no matter the depth of the namespace?
This function is somewhat close, only it modifies the original object which we don't want ofcourse:
var get = function(obj, namespace, key, value) {
var parts = namespace.split('.');
for(var i = 0; i < parts.length; i++) {
if(typeof obj[parts[i]] == 'undefined'){
obj[parts[i]] = {};
}
obj = obj[parts[i]];
}
return obj[key] = value;
};
Reason for the madness is that I cannot expose the object. It must remain private and a public method must spit out a result.
Give this a try.
function get(namespace, key) {
var parts = namespace.split('.'),
i = 0,
l = parts.length,
obj = o;
while ( i < l ) {
obj = obj[parts[i]];
if ( ! obj ) break;
i++;
}
return obj && obj[key] ? obj[key] : null;
}
I have created a fiddle with working code. Hope that helps.
http://jsfiddle.net/RdhJF/2/
var o = {
map: {
lat : -33.86749,
lng : 151.20699,
zoom : 12
},
filters : {
animals : {
dogs: {
myDog : 'fido'
}
}
}
};
function get(obj, namespace)
{
var parts = namespace.split('.');
if(parts.length==0)
return -1;
var previousValue = obj;
for(var i = 0; i < parts.length; i++)
{
if(typeof previousValue[parts[i]] == 'undefined')
return -1;
else
previousValue = previousValue[parts[i]];
}
return previousValue;
}
var myValue= get(o,'filters.animals.dogs.myDog');
alert(myValue);

Adding a value to a jquery tree object

Suppose I have an object like that.
var t = {
"obj1": {
"obj1.1": "test",
"obj1.2": {
"obj1.1.1": null, // <-- "obj1.1.1" has to have a value.
"obj1.1.2": "test"
}
}
};
And a path to the node where I'd like to add a value, i.e.:
var path = ['obj1', 'obj1.1', 'test'];
How do I add the value programmatically?
Try this:
function setDeepValue(obj, value, path) {
if(path.length > 1){
var p=path.shift();
if(obj[p]==null || typeof obj[p]!== 'object'){
obj[p] = {};
}
setDeepValue(obj[p], value, path);
}else{
obj[path[0]] = value;
}
}
var obj = {};
var path = ['obj1', 'obj1.1'];
setDeepValue(obj, 'test', path);
console.log(obj); // {"obj1":{"obj1.1":"test"}}
You will however need to fix your object:
var t = {
"obj1": {
"obj1.1": "test",
"obj1.2": {
"obj1.1.1": null, // <-- "obj1.1.1" has to have a value.
"obj1.1.2": "test"
}
}
};
A object can't have a key without a value, so "obj1.1.1" will have to have a value, even if it's null.
Supposing this object
var obj = {
"obj1" : {
"obj1.1" : "",
"obj1.2" : {
"obj1.1.1" : "",
"obj1.1.2" : ""
}
}
}
var path = ['obj1', 'obj1.1', 'test'];
the algorithm is:
var el = obj;
for(var i = 0; i < path.length-2; i++) {
el = el[path[i]];
}
el[path[i]] = path[i+1];
or as function
function setpath(obj,path) {
var el = obj;
for(var i = 0; i < path.length-2; i++) {
console.log(i+"="+path[i]);
el = el[path[i]];
}
el[path[i]] = path[i+1];
console.log(el);
}
setpath(obj,['obj1', 'obj1.1', 'test']);
var tree = {
"obj1": {
"obj1.1": "test",
"obj1.2": {
"obj1.1.1": null,
"obj1.1.2": "test"
}
}
};
var path = ['obj1', 'obj1.1', 'test'];
A static way of setting 'test':
tree[path[0]][path[1]] = path[2];
A static way of replacing 'test' with newObj:
var newObj = { ... };
tree[path[0]][path[1]][path[2]] = newObj;

Categories