How can I build this XML structure in JSON through JavaScript? - javascript

I have this XML structure that I wish to construct in JSON format using JavaScript - preferably using dot notation all the way if possible. :)
Here is the XML - note this is a pseudo structure, to keep it simple! :)
<Items>
<Item>
<Name>Item 1</Name>
<SubItems>
<Item>
<Name>Sub Item 1</Name>
</Item>
</SubItems>
</Item>
<Item>
<Name>Item 2</Name>
</Item>
</Items>
So, when I convert my JSON to XML (on the server), the output should be like above.
I need help getting started with this. I Google'd around and I couldn't find any examples on how to do this.
Thanks in advance!
EDIT: I am using NewtonSoft JSON for .NET to convert from JSON to XML!
EDIT 2: Ok, I figured out the Raw JSON structure to get the convertion to XML right - here it is:
var json = {
"Items":
{
"Item":
[
{
"Name": "Test 1" ,
"SubItems":
{
"Item":
[
{
"Name":"Test 1"
},
{
"Name":"Test 2"
}
]
}
},
{
"Name":"Test 2"
}
]
}
};
That will produce the exact same XML structure as defined above.
Now, how would I go about building this structure using dot notation?
EDIT 3: With the help of Nikhil & Darin, I figured it out, however this only answers the pseudo-question. However I will mark this as answered and create a new question. :)
EDIT 4: I posted my extension to the marked answer. :)

this should do it:
var items = [
{"name":"Item 1","subitems":[
{"name":"Subitem 1"}
]},
{"name":"Item 2"}
];

var items = [ ];
var item1 = { };
item1.Name = 'Item 1';
item1.SubItems = [ ];
var subItem = { };
subItem.Name = 'Sub Item 1';
item1.SubItems.push(subItem);
items.push(item1);
var item2 = { };
item2.Name = 'Item 2';
items.push(item2);

var json = {};
json.Items = {};
json.Items.Item = new Array();
var item1 = {};
item1.Name = "Test 1"
item1.SubItems = new Array();
var subItem1 = {};
subItem1.Item = new Array();
subSubItem1 = {};
subSubItem1.Name = "Test 1";
subSubItem2 = {};
subSubItem2.Name = "Test 2";
subItem1.Item.push(subSubItem1);
subItem1.Item.push(subSubItem2);
item1.SubItems.push(subItem1);
var item2 = {};
item2.Name = "Test 2";
json.Items.Item.push(item1);
json.Items.Item.push(item2);
Output of the above code is
{
"Items": {
"Item": [
{
"Name": "Test 1",
"SubItems": [
{
"Item": [
{
"Name": "Test 1"
},
{
"Name": "Test 2"
}
]
}
]
},
{
"Name": "Test 2"
}
]
}
}
that should do it :)

Nikhil answered the question, and has gotten the magic tick. :) - I am extending his answer with the code I wrote to get the result I was looking for.
My real problem, after receiving the answer to the pseudo problem, was that I have different item types in my structure, which all shared the Items root node.
Here is a pseudo example of how I solved the issue. Again, Nikhil's answer was the base of the solution, so many thanks to him :)
Say we have a rootnode, Fruits, and we have different types of fruit. Say, apple, and banana.
Here's how I got the JSON structure (and ultimately, the XML convertion output that I was needing):
// Create the JSON Object
var json = {};
// Create the Fruits Objects (Our root)
json.Fruits = {};
for (var i = 0; i < 3; i++){
// Pseudo condition
if (i == 0 || i == 1) {
// Make sure we have an Apple array
if(json.Fruits.Apple == undefined)
json.Fruits.Apple = [];
json.Fruits.Apple.push({
"Color": "Green"
});
} else {
// Make sure we have a Banana array
if (json.Fruits.Banana == undefined)
json.Fruits.Banana = [];
json.Fruits.Banana.push({
"Color": "Yellow"
});
}
}
This will output the following JSON:
{"Fruits":
{"Apple":
[
{"Color":"Green"},
{"Color":"Green"}
],
"Banana":
[
{"Color":"Yellow"}
]
}
}
And ultimately, the following XML:
<Fruits>
<Apple>
<Color>Green</Color>
</Apple>
<Apple>
<Color>Green</Color>
</Apple>
<Banana>
<Color>Yellow</Color>
</Banana>
</Fruits>

Related

Adding two new elements to existing JSON array

I have the following JavaScript object which prints the following JSON using
var str = JSON.stringify(finalNodesData, null, 2);
console.log(str);
Printed JSON
[
{
"jobDate": "2023-01-03 13:48:29.402",
"id": "b186c313-a2f3-44a8-9803-066c6d52e8a0"
},
{
"jobDate": "2023-01-03 13:57:19.988",
"id": "db182f5e-9622-42e9-bbe8-19bee4d878d4"
}
]
How can I add two new elements "submitedBy" and "submitReason" to the JSON? I want my JSON to look like
{
"submitedBy": "Bob Smith",
"submitReason": "Because of an error",
"nodeData": [
{
"jobDate": "2023-01-03 13:48:29.402",
"id": "b186c313-a2f3-44a8-9803-066c6d52e8a0"
},
{
"jobDate": "2023-01-03 13:57:19.988",
"id": "db182f5e-9622-42e9-bbe8-19bee4d878d4"
}
]
}
I want to use JavaScript variables to generate the JSON, and not concatenate strings.
Note: Your new JSON is no longer an Array, but an Object.
finalNodesData = {};
finalNodesData["nodeData"] = nodeData; // this is your old data
finalNodesData["submitedBy"] = "Bob Smith";
finalNodesData["submitReason"] = "Because of an error";
var str = JSON.stringify(finalNodesData, null, 2);
console.log(str);
The best way of doing this is adding the data to the JavaScript object before converting it to JSON.
let finalNodesData = [
{
jobDate: "2023-01-03 13:48:29.402",
id: "b186c313-a2f3-44a8-9803-066c6d52e8a0"
},
{
jobDate: "2023-01-03 13:57:19.988",
id: "db182f5e-9622-42e9-bbe8-19bee4d878d4"
}
]
const submittedBy = "Bob Smith"
const submitReason = "Because of an error"
finalNodesData = {
submittedBy,
submitReason,
nodeData: finalNodesData
}
var str = JSON.stringify(finalNodesData, null, 2);
console.log(str);

Print the same child nodes from an object but two levels deep

I'm trying to create a piece of JavaScript that can read through specific parts of a linked object and place them iteratively into another piece of code which then places the code into HTML and into the front-end.
I've managed to get the fetch part working whereby it pulls in the JSON and can be read in the console, when summoned. Once the code runs, I'm able to refer to the data and bring out the whole dataset with something like:
console.log(AllOffers);
and I can drill down into something like the offerName in the JSON by using the following syntax in a variable and calling it in the console:
var OfferName = data.offersBreakdown.allOffers[0].offers[0].offerName;
However this only pulls in the first iteration of offerName because in the variable I've set it to look into the first iteration of its parent, 'offers'. What I'm looking to do is create a variable which prints all of the offerName data so that I can call on it instead of the data_test variable further down in the code, which processes the data into HTML. Sounds confusing? It is.
Ideally what I think I need is to be able to ask it to look into each child item of 'offers' (rather than just the first one) and then have it look for 'offerName'. I can't work out how one would achieve this. The best I can come up with is to remove the [0] from 'offers', but if I do that, it returns undefined as the result.
Here's my JavaScript (and a bit of jQuery):
<script>
// fetch call for the JSON data (see below)
fetch('api_url', {
headers: {
'Authorization': 'auth_token'
}
})
.then(response => response.json())
.then(function (data) {
var AllOffers = data.offersBreakdown.allOffers[0];
var AllOffers_Offers = data.offersBreakdown.allOffers[0].offers;
var OfferName = data.offersBreakdown.allOffers[0].offers[0].offerName;
var OfferImageUrl = data.offersBreakdown.allOffers[0].offers[0].imageUrl;
console.log(AllOffers);
function createCard(cardData) {
var cardTemplate = [
'<div class="card">',
'<p>My name is: ',
cardData.Offer || 'No offer',
'</p>',
'<p>My job is: ',
cardData.Img || 'No image',
'</p></div>'
];
// a jQuery node
return jQuery(cardTemplate.join(''));
}
var data_test = [
{ "Name": OfferName, "Img": OfferImageUrl },
{ "Name": OfferName, "Img": OfferImageUrl },
{ "Name": OfferName, "Img": OfferImageUrl },
];
var cards = jQuery();
// Store all the card nodes
data_test.forEach(function(item, i) {
cards = cards.add(createCard(item));
});
// Add them to the page... for instance the <body>
jQuery(function() {
jQuery('body').append(cards);
});
</script>
Here's the JSON
<script>
// the JSON
{
"offersBreakdown": {
"totalAddedOffers": 0,
"totalOffers": 2,
"totalAddedRewards": 0,
"totalRewards": 0,
"totalAddedStreakOffers": 0,
"totalStreakOffers": 0,
"allOffers": [
{
"offers": [
{
"offerName": "Offer name 1",
"imageUrl": "https://url_path_1.jpg"
},
{
"offerName": "Offer name 2",
"imageUrl": "https://url_path_2.jpg"
},
{
"offerName": "Offer name 3",
"imageUrl": "https://url_path_3.jpg"
},
{
"offerName": "Offer name 4",
"imageUrl": "https://url_path_4.jpg"
}
]
}
</script>
I'm assuming what you're looking for is a way to loop through all of the offerNames, in which case a simple for loop would suffice. Since your data includes nested arrays and objects, we need two loops, one to iterate through your allOffers array and then a nested for loops to iterate through the offers array inside of your allOffers array
var data = {
"offersBreakdown": {
"totalAddedOffers": 0,
"totalOffers": 2,
"totalAddedRewards": 0,
"totalRewards": 0,
"totalAddedStreakOffers": 0,
"totalStreakOffers": 0,
"allOffers": [{
"offers": [{
"offerName": "Offer name 1",
"imageUrl": "https://url_path_1.jpg"
}, {
"offerName": "Offer name 2",
"imageUrl": "https://url_path_2.jpg"
}, {
"offerName": "Offer name 3",
"imageUrl": "https://url_path_3.jpg"
}, {
"offerName": "Offer name 4",
"imageUrl": "https://url_path_4.jpg"
}]
}]
}
};
var allOffers = [];
var jsonObjectAllOffers = data.offersBreakdown.allOffers;
for (var i = 0; i < jsonObjectAllOffers.length; i++) {
var offers = jsonObjectAllOffers[i].offers;
for (var j = 0; j < offers.length; j++) {
var objectToAppend = {
"Name": offers[j]["offerName"],
"Img": offers[j]["imageUrl"]
};
allOffers.push(objectToAppend);
}
}
console.log(allOffers);
And now you can use your allOffers variable to loop through with the "forEach" and make into HTML

Array Mapping in AngularJs

I have two arrays
$scope.tags = [{ "id": 1, "name": "python" }, { "id": 2, "name": "NodeJs" }, { "id": 3, "name": "git" }]
Other one is
$scope.skillsInterested = [1,2];
What is want to do ?
How can i map the above arrays and print only names of the id's in$scope.skillsInterested
I want to print names in first array only the id's present in second.
I have tried this after getting several answers
var tag_map = {};
for (var x = 0; x < $scope.tags.length; x++) {
tag_map[$scope.tags[x]['id']] = $scope.tags[x]['name'];
}
$scope.skillsInts = $scope.skillsInterested.map(function(x) {
return tag_map[x]
On running console.log
console.log("Result", tag_map);
It sometimes give result sometimes it gives 'map' of undefined.
TypeError: Cannot read property 'map' of undefined
at controllers.js:141
at angular.js:16383
at m.$eval (angular.js:17682)
at m.$digest (angular.js:17495)
at m.$apply (angular.js:17790)
at l (angular.js:11831)
at J (angular.js:12033)
at XMLHttpRequest.t.onload (angular.js:11966)
Thanks in advance.
Make a map of your data that looks like this:
var tagMap = { 1: "python", 2: "NodeJs" /* etc. */ };
You can do this by looping over your tags and adding a new property to an object. reduce lets you do this without creating any extra variables.
Then, you can select names from your newly created object using the [] notation: tagMap[1] returns "pyhton".
var tags = [{ "id": 1, "name": "python" }, { "id": 2, "name": "NodeJs" }, { "id": 3, "name": "git" }]
var selectedExpTags = [1,2];
// Make a map for `id: name`
var tagMap = tags.reduce(function(map, tag) {
map[tag.id] = tag.name;
return map;
}, {});
// Quickly select names from the map:
var selectedNames = selectedExpTags.map(function(id) {
return tagMap[id];
});
console.log(selectedNames);
Using this approach, you minimise the iterations over your data. The creation of the map loops over the tags once. Creating the array with names, loops over the selected tags once. So, roughly, the "loop count" is tags.length + selectedTags.length. If you would use an indexOf based approach, your loop count would be tags.length * selectedTags.length.
Use the filter function for first, and then check the id's existnent then map the names from the array.
var first = [{ "id": 1, "name": "python" }, { "id": 2, "name": "NodeJs" }, { "id": 3, "name": "git" }];
var selectedExpTags = [1,2];
var names = first.filter(item => selectedExpTags.some(id => item.id === id)).map(item => item.name);
console.log(names);
You can loop over $scope.selectedExpTags and get a list of all names. You can use array.find if you want first value only.
Sample
var first = [
{ "id": 1, "name": "python" },
{ "id": 2, "name": "NodeJs" },
{ "id": 3, "name": "git" }];
var selectedExpTags = [1,2];
var names = selectedExpTags.map(x=> first.find( y=> y.id === x ).name )
console.log(names);
$scope.newArray = []; // If you need a new array to work with
angular.forEach($scope.tags, function(tag){
$scope.selectedExpTags.forEach(function(selectedTag){
if(selectedTag == tag.id){
//tag.hide = false; // - If you want to update the current array
$scope.newArray.push(tag);
}
// else{ // - If you want to update the current array
// tag.hide = true;
// }
})
})
Lodash is more efficient than angular for manipulating data.

javascript: looping through nested object/array and adding property

I am not very strong with Javascript. I have a nested array which is a JSON representation of the backend data. It shows a list of proofs and the images used in each proof. Its looks like below:
var project = [{
"proof":"Proof_1",
"images":[
{
"image_id":"12469",
"name":"1911791794.jpg",
},
{
"image_id":"12470",
"name":"1911802897.jpg"
},
{
"image_id":"12471",
"name":"1911761073.jpg"
}
},
{
"proof":"Proof_2",
"images":[
{
"image_id":"12469",
"name":"1911791794.jpg",
},
{
"image_id":"12470",
"name":"1911802897.jpg"
}
}];
I want to add the image_count to each proof section,so that modified data structure looks like this:
var project = [{
"proof":"Proof_1",
"image_count": 3, //<----this is new property I want to add
"images":[
{
"image_id":"12469",
...
I checked some answers but because of my lack of understanding javascript iteration properly I am unable to get this done.
When I do:
for (var proof in project)
{
console.log(proof);
}
I just get 0,1,2...etc printed. I am not getting this, so I help someone in SO will help me understand how to add this property I want.
Thanks in advance.
You can take advantage of Array.prototype.map method:
project = project.map(function (item) {
item.image_count = item.images.length;
return item;
});
Working demo.
Also, as #Sebastian Lasse pointed out - you should name your array using plural form to avoid confusion (projects instead of project).
You can use .map or simple loop
var projects = [{
"proof": "Proof_1",
"images": [{
"image_id": "12469",
"name": "1911791794.jpg",
}, {
"image_id": "12470",
"name": "1911802897.jpg"
}, {
"image_id": "12471",
"name": "1911761073.jpg"
}]
}, {
"proof": "Proof_2",
"images": [{
"image_id": "12469",
"name": "1911791794.jpg",
}, {
"image_id": "12470",
"name": "1911802897.jpg"
}]
}];
projects = projects.map(function (element) {
element.image_count = element.images.length;
return element;
});
console.log(projects);
var len = projects.length, i;
for (i = 0; i < len; i++) {
projects[i].image_count = projects[i].images.length;
}
console.log(projects);
You could - after correcting the missing ] error in your JSON - do this :
project.forEach(function(proof) {
proof.image_count = proof.images.length;
})
demo -> http://jsfiddle.net/dLd8wvpb/

Accessing JSON array's through object properites

Let's say I have the next JSON file:
{
"shows": [
{
"name": "House of cards",
"rating": 8
},
{
"name": "Breaking bad",
"rating": 10
}
]
}
I want to access the rating of a show, by it's name. Something like this:
var rating = data.shows["House of cards"].rating;
Is this possible? Or something similar?
Thanks a lot!
You won't have such hash-style access just by deserializing that JSON sample.
Maybe you might be able to re-formulate how the data is serialized into JSON and use object literals even for shows:
{
"shows": {
"House of cards": {
"rating": 8
}
}
}
And you can still obtain an array of show keys using Object.keys(...):
Object.keys(x.shows);
Or you can even change the structure once you deserialize that JSON:
var x = { shows: {} };
for(var index in some.shows) {
x.shows[some.shows[index].name] = { rating: some.shows[index].rating };
}
// Accessing a show
var rating = x.shows["House of cards"].rating;
I suggest you that it should be better to do this conversion and gain the benefit of accessing your shows using plain JavaScript, rather than having to iterate the whole show array to find one.
When you use object literals, you're accessing properties like a dictionary/hash table, which makes no use of any search function behind the scenes.
Update
OP has concerns about how to iterate shows once it's an associative array/object instead of regular array:
Object.keys(shows).forEach(function(showTitle) {
// Do stuff here for each iteration
});
Or...
for(var showTitle in shows) {
// Do stuff here for each iteration
}
Update 2
Here's a working sample on jsFiddle: http://jsfiddle.net/dst4U/
Try
var rating = {
"shows": [
{
"name": "House of cards",
"rating": 8
},
{
"name": "Breaking bad",
"rating": 10
}
]
};
rating.shows.forEach(findsearchkey);
function findsearchkey(element, index, array) {
if( element.name == 'House of cards' ) {
console.log( array[index].rating );
}
}
Fiddle
var data = {"shows": [{"name": "House of cards","rating": 8},{"name": "Breaking bad","rating": 10}]};
var shows = data.shows;
var showOfRatingToBeFound = "House of cards";
for(var a in shows){
if(shows[a].name == showOfRatingToBeFound){
alert("Rating Of "+ showOfRatingToBeFound+ " is " +shows[a].rating);
}
}

Categories