Transform nested arrays into a structured HTML format

For the past few days, I've been grappling with a seemingly "simple" exercise that has left me feeling incredibly stuck and frustrated. The task at hand involves converting nested arrays into HTML format. To illustrate, consider the following array:

const data = ['html', [
  ['head', [
    ['title', 'Your title text goes here'],
  ]],
  ['body', { class: 'container' }, [
    ['h1', { class: 'header' }, 'h1 text'],
    ['div', [
      ['span', 'span text2'],
      ['span', 'span text3'],
    ]],
  ]],
]];

The desired output should resemble the following HTML structure:

<html>
  <head>
    <title>your title text</title>
  </head>
  <body class="container">
    <h1 class="header">h1 text</h1>
    <div>
      <span>span text2</span>
      <span>span text3</span>
    </div>
  </body>
</html>

A helper function, tagBuilder, has been implemented to create each HTML tag from an array. Here is the current implementation:

const tagBuilder = (arr) => {
  console.log(arr)
  // Logic for creating tags from Array elements
}

The challenge arises when attempting to construct the actual HTML builder function that can iterate through each element of the array, handle nested elements, and construct the appropriate HTML structure:

const buildHTML = (array) => {
  // Initial attempt with a placeholder implementation
}

I have encountered difficulties in handling nested arrays within the main array while constructing the HTML structure. Although I have experimented with methods like reduce and nested map, I have yet to find a satisfactory solution. I believe that the final function should resemble the following design:

// Sample nested array
const textAndArrChild = ['div',
['span', 'span text3']];
// Expected result: <div><span>span text3</span></div>

// Implementation of tagBuilder function
const tagBuilder = (arr) => {
  // Logic for creating tags based on array content
}

// Implementation of buildHTML function
const buildHTML = (array) => {
  // Logic for building HTML from nested arrays
}

console.log(buildHTML(textAndArrChild))

Answer №1

⚠️
⚠️⚠️
⚠️⚠️⚠️

It is crucial to note that generating HTML in this manner poses a significant security risk, unless it is for educational purposes. It is recommended to utilize a templating library like which automatically implements encoding and escaping.

⚠️⚠️⚠️
⚠️⚠️
⚠️


To simplify the process, consider adjusting the data structure representing a tag:

[tag-name tag-attribute children*]

This structure includes a child element that can either be a plain text or another tag data structure. For instance:

  ['html', {},
    ['head', {},
      ['title', {}, 'Your title text goes here']],
    ['body', { class: 'container' },
      ['h1', { class: 'header' }, 'h1 text'],
      ['div', {},
        ['span', {}, 'span text2'],
        ['span', {}, 'span text3']]]]

We have eliminated an unnecessary wrapper [] around the children in exchange for a compulsory attribute parameter represented by {} when not needed. Overall, it seems like a reasonable tradeoff.

If we adopt this convention, we can create a function called tag as follows:

const tag = (name, attr, ...children) => {
  // ...
};

Given that we are dealing with nested tags, utilizing recursion appears to be the most practical approach for generating complete markup:

const tag = (name, attr, ...children) => `
  <${name} ${Object.entries(attr).map(([n, v]) => `${n}="${v}"`).join(' ')}>
    ${children.map(child => typeof child === 'string' ? child : tag(...child)).join("\n")}
  </${name}>
`;

console.log(tag(...markup))
<script>
const markup =
  ['html', {},
    ['head', {},
      ['title', {}, 'Your title text goes here']],
    ['body', { class: 'container' },
      ['h1', { class: 'header' }, 'h1 text'],
      ['div', {},
        ['span', {}, 'span text2'],
        ['span', {}, 'span text3']]]];
</script>

Answer №2

To simplify things greatly, we can remove the formatting indents to create a cleaner version.

const info = ['html', [
  ['head', [
    ['title', 'Enter your title here'],
  ]],
  ['body', { class: 'container' }, [
    ['h1', { class: 'header' }, 'Heading 1 text'],
    ['div', [
      ['span', 'Span text 2'],
      ['span', 'Span text 3'],
    ]],
  ]],
]];

const display = info =>{
  let element, attributes, children;
  
  if(info.length === 2){
    [element, children] = info;
  } else if(info.length === 3){
    [element, attributes, children] = info;
  } 

  let attrString = ""
  for(let attr in attributes){
    attrString += " " + attr + '="' + attributes[attr] + '"';
  }
  
  let childString = ""
  if(typeof children !== "string"){
      for(let child of children){
        childString += display(child);
      }
  } else {
    childString = children;
  }
  
  return (`<${element}${attrString}>${childString}</${element}>`)
}

console.log(display(info))

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

AngularJS ng-show will not function properly with newly added DOM elements

I am encountering an issue with ng-show directives on dynamically added DOM elements in AngularJS. The directives work fine when the page initially loads, but new elements that are added later do not have their expressions evaluated. Is there a way to prom ...

The HTML elements in my JSX code seem to constantly shift around whenever I resize my webpage

Using react.js, I'm currently developing a website that appears like this before resizing: pre-resize_screenshot_website However, upon vertical or diagonal resizing, the layout becomes distorted especially in the 'availability search bar' ...

The controller is unable to retrieve the posted value

Whenever I try to retrieve the post value from my controller, it always returns null. Even though I can see that there is a post value present when I check, for some reason, I am not able to access that value in my controller. Does anyone know what the p ...

Exploring the world of jQuery and Ajax: Experimenting with implementing a POST method through Ajax and retrieving the response in HTML

Hey guys, I'm currently attempting to set up a basic HTML post method using Ajax. Take a look at the code snippet below: <?PHP function fetchInstagramData($url) { $ch = curl_init(); curl_setopt_array($ch, array( CURLOPT_URL => ...

I can't seem to figure out why I keep running into a 403 error and why my Delete API isn't functioning

Need Assistance as a Beginner Working on a MERN Project and struggling with making the Delete API function from the front-end. The Delete API works perfectly when tested through Postman, but fails to work from the front-end. Below is the code snippet of t ...

Combining Socket.io with AJAX for real-time web applications

I am currently working on a web application that relies on Socket.io for delivering notifications to users. I'm wondering if it would be more beneficial to utilize Socket.io exclusively for all client-server communication, or if mixing in traditional ...

What is the process for creating a progress bar in PixiJS?

Can someone guide me on creating a progress bar similar to the one in PixiJS? Screenshot ...

What is the process for creating interconnected mutations in GraphQL?

Exploring GraphQL: Implementing Associated Mutations To deepen my understanding of GraphQL and expand my technical skills, I decided to create a portfolio for myself. However, as I delved into this project, I encountered a challenge when trying to add an ...

Utilizing JavaScript for loops to extract the final element from an array

I am facing an issue with the second loop within a function that goes through a JSON file. The problem is that it only returns the last item in the array. I need to figure out how to fix this because the chart object should be created on each iteration, ...

What is the best way to pass a value from PHP to ExtJs?

Is it achievable to transfer a PHP function value to my ext js backend system? Can the challenge be addressed using an Ajax request like this? Ext.Ajax.request({ url: '{url action=getSqlDetails}', params: { count: count }, Here, the $count var ...

Is it possible to include multiple URLs in a single cURL request to retrieve product information?

I am trying to retrieve products from the "generic/products" URL and the "generic/all_products" URL using a single cURL request. Here is my code: <?php $ch = curl_init(); $request_url = "HTTP://www.yourdomain.com/net/WebService.aspx?"; $request_u ...

The checkbox remained unchanged when I first tried to toggle it using ng-change

When I click on the checkbox input, nothing happens the first time. But when I click it again the function in ng-change() works as expected. I am confused. Am I missing something? <tr dir-paginate="product in kitchenProducts | itemsPerPage: 10"> ...

Adjusting the view with a sliding tool

I am new to jQuery and want to create a compact plugin for my specific needs. My goal is to develop a simple timeline plugin that looks like the example below: The green bar below contains two small rectangles that can be dragged left or right to zoom in ...

A step-by-step guide on increasing native Time variables in JavaScript

How can I dynamically and repetitively add time (both hours and minutes) in JavaScript to effectively increment a date object? There are times when I need to add minutes, or hours, or a combination of both - and I want the resulting total time to be return ...

Identifying the moment a member receives a role using my Discord bot built with discord.js

I am currently working on detecting when a user is assigned a specific role on a server. Here is the code I have been using: // Require the required discord.js classes const { token } = require('./config.json'); // Create a new client instance ...

The compatibility issue between Rails 7 and Bootstrap 5.2.3, along with importmaps JavaScript, is causing dysfunction in the

Feeling a bit lost here, as I've tried several solutions from Stack Overflow related to getting bootstrap 5.2.3 javascript to work for a dropdown menu. Importmaps seem like the best approach, although esbuild was attempted with no luck. Below is a sn ...

Convert a string in JavaScript by replacing spaces with '+' and use it as a link for a Google Search

I need to create a link to search Google with a specific text. To do this, I have to replace the spaces in the text with '+' and include it in the href attribute. Here is how it can be done in HTML: <a href="#" id="afd_gsearch">Search Goo ...

Creating a Social Media Platform with JavaScript, Bootstrap, JQuery, PHP, and Mysqil

I am currently in the process of developing a social networking platform that will have similar features as Instagram. Users will be able to log in, create posts, leave comments, like content, share posts, and send data to a server for storage or display p ...

Incrementally add a new object to an existing array of objects

I have an array of objects below. When I do a console.log, this is what I see: [Object, Object, Object] 0:Object name: "Rick" Contact: "Yes" 1:Object name:"Anjie" Contact:"No" 2:Object name:"dillan" Contact:"Maybe" Now, I wa ...

How can I align Javascript output vertically in the middle?

I am currently facing an issue with a JavaScript clock displaying in a narrow frame: <!DOCTYPE html> <HTML> <HEAD> <TITLE>Untitled</TITLE> <SCRIPT> function checkTime(i) { if (i < 10) { ...