DATA 607-Assignment 7 – HTML and JSON: CodeBase

Bikash Bhowmik —- 17-Oct-2026

Introduction

This assignment explored two commonly used data formats, HTML and JSON, and how they were used to organize and store information. The main objective was to understand the differences between these formats and learn how to import their data into R for further analysis.

For this project, I selected three books related to Data Science and manually created two files containing the same information. The HTML file presented the book details in a table, while the JSON file organized the information using key-value pairs and arrays. After creating both files, I used R to read the data into separate data frames. Finally, I compared the two data frames to verify that they contained the same information, even though the original files used different structures.

Book Selection and Data Attributes

For this assignment, I chose three books related to data science and machine learning, which were closely connected to the topics covered in this course.

The selected books were:

  1. R for Data Science (2nd Edition) – Hadley Wickham, Mine Çetinkaya-Rundel, and Garrett Grolemund
  2. Python for Data Analysis (3rd Edition) – Wes McKinney
  3. An Introduction to Statistical Learning (2nd Edition) – Gareth James, Daniela Witten, Trevor Hastie, and Robert Tibshirani

These books provided a useful dataset for exploring HTML and JSON formats. Two of the selected books had multiple authors, which satisfied the assignment requirement.

For each book, I included five attributes: title, authors, publication year, publisher, and subject. The same information was stored in both HTML and JSON files to compare how the two formats organized and represented data.

Creating the HTML File (books.html)

I manually created an HTML file named books.html to organize the information about the three selected books in a table format. The table contained a header row identifying the attributes, followed by three rows containing the details of each book. Each column represented a specific attribute, including the book title, authors, publication year, publisher, and subject.

Creating this file manually helped me better understand how HTML used table elements, rows, and columns to display structured information on a web page.

The HTML file was uploaded to GitHub and accessed in R using its raw GitHub URL.

Loaded library
library(rvest)
library(jsonlite)
library(tidyverse)

html_url <- "https://raw.githubusercontent.com/BIKASHBHOWMIK15/Data-607/main/Assignment7/books.html"

books_html <- html_url %>%
  read_html() %>%
  html_table(fill = TRUE)

books_html <- books_html[[1]]

books_html
# A tibble: 3 × 5
  title                               authors publication_year publisher subject
  <chr>                               <chr>              <int> <chr>     <chr>  
1 R for Data Science (2nd Edition)    "Hadle…             2023 O'Reilly… Data S…
2 Python for Data Analysis (3rd Edit… "Wes M…             2022 O'Reilly… Data A…
3 An Introduction to Statistical Lea… "Garet…             2021 Springer  Statis…

Creating the JSON File (books.json)

I manually created a JSON file named books.json containing the same information about the three selected books. The data was organized as an array of objects, with each object representing one book. Each book object included the same attributes used in the HTML table, such as title, authors, publication year, publisher, and subject.

Unlike HTML, which displayed information in rows and columns, JSON stored data using key-value pairs and arrays. Creating this file manually helped me understand how JSON organized structured information and how the same dataset could be stored in different formats.

json_url <- "https://raw.githubusercontent.com/BIKASHBHOWMIK15/Data-607/main/Assignment7/books.json"

books_json <- fromJSON(json_url)

books_json
                                                  title
1                      R for Data Science (2nd Edition)
2                Python for Data Analysis (3rd Edition)
3 An Introduction to Statistical Learning (2nd Edition)
                                                         authors
1       Hadley Wickham, Mine Cetinkaya-Rundel, Garrett Grolemund
2                                                   Wes McKinney
3 Gareth James, Daniela Witten, Trevor Hastie, Robert Tibshirani
  publication_year      publisher              subject
1             2023 O'Reilly Media         Data Science
2             2022 O'Reilly Media        Data Analysis
3             2021       Springer Statistical Learning

Inspect structure of both data frames

Before comparing the two datasets, I inspect their structure to verify the variable names and data types.

glimpse(books_html)
Rows: 3
Columns: 5
$ title            <chr> "R for Data Science (2nd Edition)", "Python for Data …
$ authors          <chr> "Hadley Wickham, Mine Cetinkaya-Rundel,\r\n          …
$ publication_year <int> 2023, 2022, 2021
$ publisher        <chr> "O'Reilly Media", "O'Reilly Media", "Springer"
$ subject          <chr> "Data Science", "Data Analysis", "Statistical Learnin…
glimpse(books_json)
Rows: 3
Columns: 5
$ title            <chr> "R for Data Science (2nd Edition)", "Python for Data …
$ authors          <chr> "Hadley Wickham, Mine Cetinkaya-Rundel, Garrett Grole…
$ publication_year <int> 2023, 2022, 2021
$ publisher        <chr> "O'Reilly Media", "O'Reilly Media", "Springer"
$ subject          <chr> "Data Science", "Data Analysis", "Statistical Learnin…

This step helps confirm whether both imported datasets have the same variables and whether any columns require type conversion before comparison.

Standardize data types

Because HTML and JSON imports can sometimes differ slightly in structure, I standardize both data frames by converting all columns to character type, matching column names and order, and resetting row names.

# Compare HTML and JSON datasets

# Standardize column names
clean_names <- function(x) {
  x <- tolower(trimws(x))
  x <- gsub("[^a-z0-9]+", "_", x)
  x <- gsub("^_|_$", "", x)
  x
}

names(books_html) <- clean_names(names(books_html))
names(books_json) <- clean_names(names(books_json))

# Expected fields
expected_cols <- c(
  "title", "authors", "publication_year",
  "publisher", "subject"
)

# Display imported column names
cat("HTML columns:\n")
HTML columns:
print(names(books_html))
[1] "title"            "authors"          "publication_year" "publisher"       
[5] "subject"         
cat("JSON columns:\n")
JSON columns:
print(names(books_json))
[1] "title"            "authors"          "publication_year" "publisher"       
[5] "subject"         
# Check that both datasets contain the required fields
missing_html <- setdiff(expected_cols, names(books_html))
missing_json <- setdiff(expected_cols, names(books_json))

if (length(missing_html) > 0 || length(missing_json) > 0) {
  cat("Missing HTML columns:", paste(missing_html, collapse = ", "), "\n")
  cat("Missing JSON columns:", paste(missing_json, collapse = ", "), "\n")
  stop("Column mismatch: check the imported datasets.")
}

# Select matching columns
html_compare <- books_html[, expected_cols, drop = FALSE]
json_compare <- books_json[, expected_cols, drop = FALSE]

# Convert author arrays to comma-separated text
normalize_authors <- function(x) {
  if (is.list(x)) {
    x <- vapply(
      x,
      function(a) paste(unlist(a), collapse = ", "),
      character(1)
    )
  }

  gsub("\\s+", " ", trimws(as.character(x)))
}

html_compare$authors <- normalize_authors(html_compare$authors)
json_compare$authors <- normalize_authors(json_compare$authors)

# Standardize remaining fields
for (col in c("title", "publisher", "subject")) {
  html_compare[[col]] <- trimws(as.character(html_compare[[col]]))
  json_compare[[col]] <- trimws(as.character(json_compare[[col]]))
}

html_compare$publication_year <- as.numeric(
  html_compare$publication_year
)

json_compare$publication_year <- as.numeric(
  json_compare$publication_year
)

# Compare the two datasets
comparison_result <- all.equal(
  html_compare,
  json_compare,
  check.attributes = FALSE
)

cat("\nComparison result:\n")

Comparison result:
print(comparison_result)
[1] TRUE
# Display both datasets
knitr::kable(
  html_compare,
  caption = "Books Imported from HTML"
)
Books Imported from HTML
title authors publication_year publisher subject
R for Data Science (2nd Edition) Hadley Wickham, Mine Cetinkaya-Rundel, Garrett Grolemund 2023 O’Reilly Media Data Science
Python for Data Analysis (3rd Edition) Wes McKinney 2022 O’Reilly Media Data Analysis
An Introduction to Statistical Learning (2nd Edition) Gareth James, Daniela Witten, Trevor Hastie, Robert Tibshirani 2021 Springer Statistical Learning
knitr::kable(
  json_compare,
  caption = "Books Imported from JSON"
)
Books Imported from JSON
title authors publication_year publisher subject
R for Data Science (2nd Edition) Hadley Wickham, Mine Cetinkaya-Rundel, Garrett Grolemund 2023 O’Reilly Media Data Science
Python for Data Analysis (3rd Edition) Wes McKinney 2022 O’Reilly Media Data Analysis
An Introduction to Statistical Learning (2nd Edition) Gareth James, Daniela Witten, Trevor Hastie, Robert Tibshirani 2021 Springer Statistical Learning

Final Output

After this step, both data frames are aligned for a strict comparison.

Compare the two data frames using identical() The identical() function checks whether the two data frames are exactly the same in both values and structure.

# Convert both objects to standard data frames
html_compare <- as.data.frame(html_compare)
json_compare <- as.data.frame(json_compare)


# Check the structure of both datasets
str(html_compare)
'data.frame':   3 obs. of  5 variables:
 $ title           : chr  "R for Data Science (2nd Edition)" "Python for Data Analysis (3rd Edition)" "An Introduction to Statistical Learning (2nd Edition)"
 $ authors         : chr  "Hadley Wickham, Mine Cetinkaya-Rundel, Garrett Grolemund" "Wes McKinney" "Gareth James, Daniela Witten, Trevor Hastie, Robert Tibshirani"
 $ publication_year: num  2023 2022 2021
 $ publisher       : chr  "O'Reilly Media" "O'Reilly Media" "Springer"
 $ subject         : chr  "Data Science" "Data Analysis" "Statistical Learning"
str(json_compare)
'data.frame':   3 obs. of  5 variables:
 $ title           : chr  "R for Data Science (2nd Edition)" "Python for Data Analysis (3rd Edition)" "An Introduction to Statistical Learning (2nd Edition)"
 $ authors         : chr  "Hadley Wickham, Mine Cetinkaya-Rundel, Garrett Grolemund" "Wes McKinney" "Gareth James, Daniela Witten, Trevor Hastie, Robert Tibshirani"
 $ publication_year: num  2023 2022 2021
 $ publisher       : chr  "O'Reilly Media" "O'Reilly Media" "Springer"
 $ subject         : chr  "Data Science" "Data Analysis" "Statistical Learning"
# Check column data types
sapply(html_compare, typeof)
           title          authors publication_year        publisher 
     "character"      "character"         "double"      "character" 
         subject 
     "character" 
sapply(json_compare, typeof)
           title          authors publication_year        publisher 
     "character"      "character"         "double"      "character" 
         subject 
     "character" 
# Check row names
rownames(html_compare)
[1] "1" "2" "3"
rownames(json_compare)
[1] "1" "2" "3"
identical_result <- identical(html_compare, json_compare)

cat("Are the standardized datasets identical? ",
    identical_result, "\n")
Are the standardized datasets identical?  TRUE 

If the result is TRUE, then both the HTML and JSON files produce exactly the same data frame in R.

Compare the two data frames using all.equal() To provide an additional check, I also use all.equal(), which is slightly more flexible and can help identify minor structural differences if they exist.

# Compare standardized datasets using all.equal()
all_equal_result <- all.equal(
  html_compare,
  json_compare,
  check.attributes = FALSE
)

cat("Are the standardized datasets equivalent? ",
    isTRUE(all_equal_result), "\n")
Are the standardized datasets equivalent?  TRUE 
# Display comparison details
print(all_equal_result)
[1] TRUE

If the result returned TRUE, it confirmed that the two imported datasets were equivalent.

Display final combined comparison view To make the comparison more transparent, I print both data frames again after type alignment.

knitr::kable(
  html_compare,
  format = "html",
  caption = "Book Data Imported from HTML",
  row.names = FALSE,
  align = c("l", "l", "c", "l", "l")
)
Book Data Imported from HTML
title authors publication_year publisher subject
R for Data Science (2nd Edition) Hadley Wickham, Mine Cetinkaya-Rundel, Garrett Grolemund 2023 O’Reilly Media Data Science
Python for Data Analysis (3rd Edition) Wes McKinney 2022 O’Reilly Media Data Analysis
An Introduction to Statistical Learning (2nd Edition) Gareth James, Daniela Witten, Trevor Hastie, Robert Tibshirani 2021 Springer Statistical Learning
knitr::kable(
  json_compare,
  format = "html",
  caption = "Book Data Imported from JSON",
  row.names = FALSE,
  align = c("l", "l", "c", "l", "l")
)
Book Data Imported from JSON
title authors publication_year publisher subject
R for Data Science (2nd Edition) Hadley Wickham, Mine Cetinkaya-Rundel, Garrett Grolemund 2023 O’Reilly Media Data Science
Python for Data Analysis (3rd Edition) Wes McKinney 2022 O’Reilly Media Data Analysis
An Introduction to Statistical Learning (2nd Edition) Gareth James, Daniela Witten, Trevor Hastie, Robert Tibshirani 2021 Springer Statistical Learning


These tables show that both source files contain the same book information after being imported into R.

HTML vs. JSON

Feature HTML JSON
Full name HyperText Markup Language JavaScript Object Notation
Main purpose Display content on web pages Store and exchange structured data
Structure Tags such as <table>, <tr>, and <td> Objects {} and arrays []
Human readability Readable, but contains many tags Generally concise and easy to read
Data types Table cells are usually extracted as text Supports strings, numbers, booleans, arrays, objects, and null
Data extraction in R rvest jsonlite
Common applications Websites and web tables Web APIs, application integration, and data exchange
Best suited for Presenting information to users Transferring structured data between systems

Conclusion

This assignment demonstrated how the same dataset could be represented in both HTML and JSON formats and then imported into R for comparison. The HTML file stored the data in a table, while the JSON file stored the same information in a structured object format.

After loading both files into R and standardizing their structures, both identical() and all.equal() returned TRUE, confirming that the two formats produced the same final data frame. This exercise helped reinforce my understanding of the structural differences between HTML and JSON while demonstrating that both formats could serve as valid data sources for downstream analysis in R.