convert html code to Json array using JavaScript function - javascript

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);

Related

TypeError: Cannot convert undefined or null to object, javascript

Exception from Finished function when I run it: TypeError: Undefined or null cannot be converted to object,
It gives this error, I couldn't find why it was caused or on which line, thanks for your help
Exception from Finished function when I run it: TypeError: Undefined or null cannot be converted to object,
It gives this error, I couldn't find why it was caused or on which line, thanks for your help
try {
fetch("https://www.tcmb.gov.tr/kurlar/today.xml")
.then((response) => response.text())
.then((data) => {
const parser = new DOMParser();
const xml = parser.parseFromString(data, "text/xml");
const jsonData = xmlToJson(xml);
const currencyData = jsonData.Tarih_Date.Currency;
currencyData.forEach(async (doviz) => {
await db.collection("currencies").add({
name: doviz.CurrencyName,
});
});
})
} catch (error) {
console.error(error);
}
My method to convert xml to json
function xmlToJson(xml) {
var obj = {};
if (xml.nodeType == 1) {
if (xml.attributes.length > 0) {
obj["#attributes"] = {};
for (var j = 0; j < xml.attributes.length; j++) {
var attribute = xml.attributes.item(j);
obj["#attributes"][attribute.nodeName] = attribute.nodeValue;
}
}
} else if (xml.nodeType == 3) {
obj = xml.nodeValue;
}
var textNodes = [].slice.call(xml.childNodes).filter(function(node) {
return node.nodeType === 3;
});
if (xml.hasChildNodes() && xml.childNodes.length === textNodes.length) {
obj = [].slice.call(xml.childNodes).reduce(function(text, node) {
return text + node.nodeValue;
}, "");
} else 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));
}
}
}
return obj;
}

How to make binary tree from array in javascript?

I have an array var array = [8,10,12,5,3,6];
Logic
First node would be root node.
If new node value is less or equal =< than parent node, It would be left node of parent node
If new node value is greater > than parent node, It would be right node of parent node
And I am trying to achieve output like below object:
{
value:8,
left:{
value:5,
left:{ value:3 },
right:{value:6}
},
right:{
value:10,
right:{value:12}
}
}
Which would be in image like this
I tried below code:
var arr = [8,10,12,5,3,6];
var root = arr[0];
var rv = {};
for (var i = 0; i < arr.length; i++){
if(arr[i] < root){
rv.left = arr[i];
}else{
rv.right = arr[i];
}
}
console.log(rv);
Please help me to solve this.
You could use a Node instance for new nodes and a function for inserting nodes.
Then iterate the values and build a new tree.
function Node(value) {
this.value = value;
// this.left = null;
// this.right = null;
}
function insertNode(tree, value) {
var node = tree,
key;
while (node.value !== value) {
key = value < node.value ? 'left' : 'right';
if (!node[key]) {
node[key] = new Node(value);
break;
}
node = node[key];
}
return tree;
}
var array = [8, 10, 12, 5, 3, 6],
tree = array.reduce((t, v) => t ? insertNode(t, v) : new Node(v), null);
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
While it is close to Nina's answer i believe to be a little more concise;
var data = [8,10,12,5,3,6],
tree;
function insertBinTree (t = {value: void 0, left: void 0, right: void 0}, n){
t.value !== void 0 ? t.value > n ? t.left = insertBinTree(t.left,n)
: t.right = insertBinTree(t.right,n)
: t.value = n;
return t;
}
tree = data.reduce(insertBinTree, void 0);
console.log(tree);
.as-console-wrapper {
max-height: 100% !important
}
Try something like this by recursive method
var binary = {};
var arr = [8,5,10,3,6,12];
function makeBinary(binary,number){
if(binary.value === undefined){
binary.value = number;
}else if(number > binary.value){
if(binary.right === undefined){
binary.right = {value:number};
}else{
binary.right = makeBinary(binary.right,number);
}
}else{
if(binary.left === undefined){
binary.left = {value:number};
}else{
binary.left = makeBinary(binary.left,number);
}
}
return binary;
}
for(let i in arr){
makeBinary(binary,arr[i]);
}
console.log(binary);
class Node {
constructor(val){
this.val=val;
this.right=null;
this.left=null;
}
}
class Bst{
constructor(){
this.root=null;
}
insert(val){
let newNode= new Node (val)
if (!this.root) this.root=newNode;
let current =this.root;
while (true) {
if(val === current.val) return undefined;
if(current.val<val){
if (current.right===null){
current.right=newNode;
return this
}
else
current=current.right}
if(current.val>val){
if (current.left===null){
current.left=newNode;
return this
}
else
current=current.left}
}
}
print (){
let all="Root=";
let visit=(current=this.root)=>{
if(!current.left && !current.right){
if(all[all.length-1]<current.val)
all+=`,LeR${current.val}`
else
all+=`,LeL${current.val}`
}
else{
if(all[all.length-1]<current.val)
all+=`,FR${current.val}`
else
all+=`,FL${current.val}`
}
if (current.left) visit(current.left)
if (current.right) visit(current.right)
}
visit()
all+=` ,valid bst:${this.isValidBST()}`
return all
}
isValidBST(node=this.root, min = null, max = null) {
if (!node) return true;
if (max !== null && node.data >= max) {
return false;
}
if (min !== null && node.data <= min) {
return false;
}
const leftSide = this.isValidBST(node.left, min, node.data);
const rightSide = this.isValidBST(node.right, node.val, max);
return leftSide && rightSide;
}
find(val){
let found=false
let innerFind=(current=this.root)=>{
if (val>current.val)
if (current.right != null) return innerFind(current.right)
if(val===current.val)
found= true
else
if (current.left != null)return innerFind(current.left)
if(val===current.val)
found= true
return found
}
return innerFind()
}
}
let tree=new Bst
tree.insert(8)
tree.insert(10)
tree.insert(13)
tree.insert(3)
tree.insert(1)
tree.insert(6)
tree.insert(4)
tree.insert(7)
tree.insert(2)
tree.print()
You can do this by technique is called recursion.
make an array with the structure ( left_subtree, key, right_subtree)
in your case
var array = [[3,5,6],8,[null,10,12]
class TreeNode {
constructor(key) {
this.key = key;
this.right = null;
this.left = null;
}
}
function parseTuple(data) {
if (data === null) {
let node = null;
return node;
}
else if (data.length === 3) {
let node = new TreeNode(data[1]);
node.left = parseTuple(data[0]);
node.right = parseTuple(data[2]);
return node;
}
else {
let node = new TreeNode(data);
return node;
}
}

Last Key in JavaScript array appearing as Length?

Bit of a weird one. Am using the following code build an array from a json object to make it easier to reference later in the code. However it would appear that when the last item of each array is created, rather than adding a new item, the Key of the item appears as the length of the array.
perfsJson = $.parseJSON(result);
var extras = new Array();
for (var i = perfsJson.length - 1; i >= 0; i--) {
var obj = perfsJson[i];
if (obj != null) {
if (obj.Extras != null) {
for (var perf_no in obj.Extras) {
if (extras[perf_no] == undefined) {
var arr = new Array();
for (var extra in obj.Extras[perf_no]) {
if (arr[extra] == undefined) {
arr[extra] = obj.Extras[perf_no][extra];
}
}
extras[perf_no] = arr;
}
}
break;
}
}
}
The resulting array appears as below:
Any ideas what's going on here?
Edit:
Sample of Json below
{"Extras":{"32516":{"24186":"Example text"},"32515":{"24186":"Example text"},"32514":{"24186":"Example text"},"32512":{"24186":"Example text"},"32513":{"24186":"Example text"},"32511":{"24186":"Example text"},"32510":{"24186":"Example text"},"32509":{"24186":"Example text"},"32507":{"24186":"Example text"},"32503":{"24186":"Example text"},"32506":{"24186":"Example text"},"32505":{"24186":"Example text"},"32508":{"24186":"Example text"},"32502":{},"32497":{}}}
What's going on hear is that you are using for..in to iterate over an array, which is a no-no because it iterates properties that are not the array elements (such as the .length property). Instead, use Array#forEach:
perfsJson = $.parseJSON(result);
var extras = new Array();
for (var i = perfsJson.length - 1; i >= 0; i--) {
var obj = perfsJson[i];
if (obj != null) {
if (obj.Extras != null) {
obj.Extras.forEach(function (item, idx) {
if (typeof extras[idx] === 'undefined') {
var arr = new Array();
item.forEach(function (item2, idx2) {
if (typeof arr[idx2] === 'undefined') {
arr[idx2] = item2;
}
});
extras[idx] = arr;
}
});
break;
}
}
}
The innermost loop is pretty pointless and can be replaced with Array#slice:
perfsJson = $.parseJSON(result);
var extras = new Array();
for (var i = perfsJson.length - 1; i >= 0; i--) {
var obj = perfsJson[i];
if (obj != null) {
if (obj.Extras != null) {
obj.Extras.forEach(function (item, idx) {
if (typeof extras[idx] === 'undefined') {
extras[idx] = item.slice();
}
});
break;
}
}
}
The next inner loop can be replaced with Array#map and two if statements can be combined:
perfsJson = $.parseJSON(result);
var extras = new Array();
for (var i = perfsJson.length - 1; i >= 0; i--) {
var obj = perfsJson[i];
if (obj != null&& obj.Extras != null) {
extras = obj.Extras.map(function (item) {
return item.slice();
});
break;
}
}
In fact, most of this code can be simplified:
function findLastElement(arr) {
for (var i = arr.length - 1; i >= 0; i -= 1) {
if (arr[i] != null && arr[i].Extras != null) { return arr[i]; }
}
}
perfsJson = $.parseJSON(result);
var lastElement = findLastElement(perfsJson);
var extras = lastElement
? lastElement.Extras.map(function (item) { return item.slice(); })
: [];

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.

parse xml with jquery - bad xml format

i have this xml file:
<dist>
<key>keynumber1</key>
<string>value1</string>
<key>keynumber2</key>
<string>value2</string>
<key>keynumber3</key>
<string>value3</string>
<key>keynumber4</key>
<integer>value4</integer>
</dist>
how can i parse this with jquery like:
{ "dist": {"keynumber1":"value1", "keynumber2":"value2"}}
Thanks a lot for help
First step is parsing xml with jQuery using $.parseXML(str);
Then I used this pretty function, created by David Welsh
function xmlToJson(xml) {
// Create the return object
var obj = {};
if (xml.nodeType == 1) { // element
// do attributes
if (xml.attributes.length > 0) {
obj["#attributes"] = {};
for (var j = 0; j < xml.attributes.length; j++) {
var attribute = xml.attributes.item(j);
obj["#attributes"][attribute.nodeName] = attribute.nodeValue;
}
}
} else if (xml.nodeType == 3) { // text
obj = xml.nodeValue;
}
// do children
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].length) == "undefined") {
var old = obj[nodeName];
obj[nodeName] = [];
obj[nodeName].push(old);
}
obj[nodeName].push(xmlToJson(item));
}
}
}
return obj;
};

Categories