DATA 607 — Week 7: HTML and JSON

Electrical Power System Analysis Books: Data Collection and Validation

Author

Patricio Romero

Published

October 17, 2026

1 Introduction

HTML and JSON are common formats used to organize and exchange information on the web. HTML is mainly used to structure web pages, while JSON is used to store and exchange structured data.

In this project, I worked with bibliographic information from three electrical engineering books related to power system analysis.

I selected this subject because my professional background is in electrical engineering. I am interested in power flow analysis, electrical distribution systems, and power system modeling.

The purpose of this project is to organize the same information in HTML and JSON formats and later compare the imported data using R.

2 Project Objectives

The main objectives of this project are:

  1. Select three books related to electrical power system analysis.
  2. Collect bibliographic information from each book.
  3. Organize the information into a structured dataset.
  4. Prepare a plan to verify the information using the Google Books API.
  5. Create HTML and JSON files containing the same information.
  6. Import both files into R.
  7. Compare the resulting data frames to verify data consistency.

3 Book Selection

I selected three books related to electrical power system analysis.

These books cover important electrical engineering topics, including power flow calculations, fault analysis, electrical system design, and system stability.

3.1 Book 1: Power System Analysis

Authors: John J. Grainger and William D. Stevenson Jr.

Year: 1994

Publisher: McGraw-Hill

ISBN: 9780070612938

This book explains the fundamentals of electrical power system analysis, including network modeling, power flow calculations, and fault analysis.

3.2 Book 2: Power System Analysis & Design, SI Version

Authors: J. Duncan Glover, Mulukutla S. Sarma, and Thomas J. Overbye

Year: 2012

Publisher: Cengage Learning

ISBN: 9781133386681

This book focuses on the analysis and design of electrical power systems. It includes power system components, transmission networks, and system operation.

3.3 Book 3: Power System Analysis

Author: Hadi Saadat

Year: 2010

Publisher: PSA Publishing

ISBN: 9780984543809

This book presents mathematical and computational methods used in power system analysis, including power flow studies, fault calculations, and stability analysis.

All three books are related to the same subject. Two of the selected books have multiple authors.

4 Data Collection

I collected bibliographic information for the three selected books.

The dataset contains five variables:

  • Title
  • Authors
  • Year
  • Publisher
  • ISBN

The information was organized into the following table.

4.1 Original Book Dataset

Title Authors Publication Year Publisher ISBN
Power System Analysis John J. Grainger; William D. Stevenson Jr. 1994 McGraw-Hill 9780070612938
Power System Analysis & Design, SI Version J. Duncan Glover; Mulukutla S. Sarma; Thomas J. Overbye 2012 Cengage Learning 9781133386681
Power System Analysis Hadi Saadat 2010 PSA Publishing 9780984543809

The dataset contains three records and five variables.

Each record represents one book, and each column represents one bibliographic attribute.

5 Data Dictionary

A data dictionary was prepared to describe the structure of the dataset.

Variable Data Type Description
Title Character Complete title of the book
Authors Character Name or names of the authors
Year Integer Publication year
Publisher Character Name of the publishing company
ISBN Character International Standard Book Number (ISBN)

The ISBN will be stored as a character variable because it is an identifier rather than a value used for mathematical calculations.

6 API Data Validation Plan

To improve data quality, I used the Google Books API to verify the bibliographic information.

The API was used to check:

  1. Book titles
  2. Author names
  3. Years
  4. Publishers
  5. ISBN numbers

I compared the information returned by the API with the original dataset.

I reviewed the differences to determine whether they were caused by abbreviations or different bibliographic information.

The API was used as an additional validation source. It did not automatically replace the original data.

This process helped identify possible differences and improve data consistency.

I accessed the Google Books API through its public Books Volumes endpoint. I first tried searching by ISBN, but the search returned errors or no results. I then used Google Books volume IDs to retrieve the records and compare their ISBN values with the original dataset.

The returned information was reviewed against the original dataset. The completed API validation and its results are presented in the Code Base section.

If an API request fails, the code reports the error instead of treating the book as verified.

7 Proposed HTML Data Structure

I created an HTML file named books.html containing a table with the bibliographic information for the three selected books.

The file will contain a table with the information from the original dataset.

The HTML table will include five columns:

  • Title
  • Authors
  • Year
  • Publisher
  • ISBN

Each row will represent one book.

The purpose of this file is to demonstrate how bibliographic information can be organized using HTML.

8 Proposed JSON Data Structure

I created a JSON file named books.json.

The JSON file contains the same three books and five variables.

Each book is represented as a JSON object containing key-value pairs.

Both files contain the same information, allowing a direct comparison after importing the data into R.

9 Data Processing and Comparison Plan

9.1 Importance of R

R is an important tool for data analysis because it allows users to import, organize, clean, and compare information from different sources.

In this project, R was used to process bibliographic information stored in HTML and JSON formats.

The rvest package was used to read the HTML table, while the jsonlite package was used to import the JSON file.

Both datasets were converted into separate data frames for comparison.

9.2 Importance of Data Frame Comparison

Comparing data frames is important because information stored in different formats may produce different results when imported into R.

For example, Years may be imported as characters in one file and integers in another file.

These differences can affect the comparison even when the original information appears to be the same.

The comparison will help identify differences in:

  • Number of records
  • Column names
  • Data types
  • Missing values
  • Bibliographic information

9.3 Proposed Comparison Method

First, I imported the HTML and JSON files into R.

Next, I reviewed the structure of both data frames and checked that they contained the same three books and five variables.

I standardized the column names, data types, and column order before comparing the datasets.

Finally, I used the identical() function in R to check whether both data frames contained exactly the same information.

The comparison results are presented in the Code Base section.

This process demonstrated how R can be used to validate data consistency across different formats.

10 Expected Results

I expect both files to produce data frames containing three records and five variables.

After importing and organizing the information, I expect the two data frames to contain identical values.

The Google Books API may help identify differences in bibliographic information, especially when books have multiple editions.

This project will help me understand how HTML and JSON represent structured data and how R can be used to import, validate, and compare information from different sources.

11 HTML and JSON Code Base

11.1 Introduction

In this section, I created and imported two files containing bibliographic information from three electrical engineering books.

The first file uses HTML, and the second file uses JSON.

The objective is to compare both datasets using R and determine whether they contain identical information.

11.2 Import HTML Data

The rvest package is used to read the HTML table.

Code
library(rvest)
library(jsonlite)

html_page <- read_html("books.html")

html_data <- html_page |>
  html_element("table") |>
  html_table()

html_data <- as.data.frame(html_data)

html_data$Year <- as.integer(html_data$Year)
html_data$ISBN <- as.character(html_data$ISBN)

knitr::kable(html_data,
  col.names = c("Title", "Authors", "Publication Year", "Publisher", "ISBN-13"),
  row.names = FALSE,
  caption = "Books Imported from HTML"
)
Books Imported from HTML
Title Authors Publication Year Publisher ISBN-13
Power System Analysis John J. Grainger; William D. Stevenson Jr. 1994 McGraw-Hill 9780070612938
Power System Analysis & Design, SI Version J. Duncan Glover; Mulukutla S. Sarma; Thomas J. Overbye 2012 Cengage Learning 9781133386681
Power System Analysis Hadi Saadat 2010 PSA Publishing 9780984543809

11.3 Import JSON Data

The jsonlite package is used to read the JSON file.

Code
json_data <- fromJSON("books.json")

json_data <- as.data.frame(json_data)

json_data$Year <- as.integer(json_data$Year)
json_data$ISBN <- as.character(json_data$ISBN)

knitr::kable(json_data,
  col.names = c("Title", "Authors", "Publication Year", "Publisher", "ISBN-13"),
  row.names = FALSE,
  caption = "Books Imported from JSON"
)
Books Imported from JSON
Title Authors Publication Year Publisher ISBN-13
Power System Analysis John J. Grainger; William D. Stevenson Jr. 1994 McGraw-Hill 9780070612938
Power System Analysis & Design, SI Version J. Duncan Glover; Mulukutla S. Sarma; Thomas J. Overbye 2012 Cengage Learning 9781133386681
Power System Analysis Hadi Saadat 2010 PSA Publishing 9780984543809

11.4 Compare Data Frames

Both datasets should contain three records and five variables.

Before comparing them, I will standardize their column order.

Code
columns <- c(
  "Title",
  "Authors",
  "Year",
  "Publisher",
  "ISBN"
)

html_data <- html_data[, columns]
json_data <- json_data[, columns]

cat("HTML dimensions:", dim(html_data), "\n")
HTML dimensions: 3 5 
Code
cat("JSON dimensions:", dim(json_data), "\n")
JSON dimensions: 3 5 
Code
identical_result <- identical(html_data, json_data)

cat("Are the data frames identical?", identical_result)
Are the data frames identical? TRUE

11.5 Data Validation

I checked the structure and missing values in both datasets.

Code
str(html_data)
'data.frame':   3 obs. of  5 variables:
 $ Title    : chr  "Power System Analysis" "Power System Analysis & Design, SI Version" "Power System Analysis"
 $ Authors  : chr  "John J. Grainger; William D. Stevenson Jr." "J. Duncan Glover; Mulukutla S. Sarma; Thomas J. Overbye" "Hadi Saadat"
 $ Year     : int  1994 2012 2010
 $ Publisher: chr  "McGraw-Hill" "Cengage Learning" "PSA Publishing"
 $ ISBN     : chr  "9780070612938" "9781133386681" "9780984543809"
Code
str(json_data)
'data.frame':   3 obs. of  5 variables:
 $ Title    : chr  "Power System Analysis" "Power System Analysis & Design, SI Version" "Power System Analysis"
 $ Authors  : chr  "John J. Grainger; William D. Stevenson Jr." "J. Duncan Glover; Mulukutla S. Sarma; Thomas J. Overbye" "Hadi Saadat"
 $ Year     : int  1994 2012 2010
 $ Publisher: chr  "McGraw-Hill" "Cengage Learning" "PSA Publishing"
 $ ISBN     : chr  "9780070612938" "9781133386681" "9780984543809"
Code
colSums(is.na(html_data))
    Title   Authors      Year Publisher      ISBN 
        0         0         0         0         0 
Code
colSums(is.na(json_data))
    Title   Authors      Year Publisher      ISBN 
        0         0         0         0         0 

11.5.1 ISBN-13 Validation

The ISBN-13 numbers were checked using the standard ISBN-13 check-digit formula.

Code
validate_isbn13 <- function(isbn) {
  isbn <- gsub("[^0-9]", "", isbn)

  if (nchar(isbn) != 13) {
    return(FALSE)
  }

  digits <- as.integer(strsplit(isbn, "")[[1]])
  weights <- rep(c(1, 3), 6)

  total <- sum(digits[1:12] * weights)
  check_digit <- (10 - (total %% 10)) %% 10

  check_digit == digits[13]
}

isbn_validation <- data.frame(
  ISBN = as.character(html_data$ISBN),
  Valid_ISBN13 = vapply(
    as.character(html_data$ISBN),
    validate_isbn13,
    logical(1)
  )
)

knitr::kable(
  isbn_validation,
  col.names = c("ISBN-13", "Valid ISBN-13"),
  row.names = FALSE,
  caption = "ISBN-13 Validation Results"
)
ISBN-13 Validation Results
ISBN-13 Valid ISBN-13
9780070612938 TRUE
9781133386681 TRUE
9780984543809 TRUE

All three ISBN-13 numbers passed the check-digit validation. This confirms that the numbers follow the ISBN-13 format, but it does not confirm the book titles or editions.

11.5.2 Google Books API Validation

I used my own Google Books API key to check the ISBN numbers in an external book database.

This validation is separate from the HTML and JSON comparison and the ISBN-13 check-digit validation.

Code
library(httr)

# The API key stays in .Renviron; never print it.
api_key <- Sys.getenv("GOOGLE_BOOKS_API_KEY")

# IDs were identified and tested using Google Books Volumes.Get.
# Each ID is paired with the expected ISBN to prevent row-order mistakes.
book_lookup <- data.frame(
  ISBN = c("9780070612938", "9781133386681", "9780984543809"),
  Google_Books_ID = c("NBIoAQAAMAAJ", "XScJAAAAQBAJ", "s_IbSQAACAAJ"),
  stringsAsFactors = FALSE
)

get_google_book <- function(isbn, id) {
  empty <- data.frame(
    ISBN = isbn, Google_Books_ID = id,
    HTTP_Status = NA_integer_, API_Status = "Connection error",
    API_Title = NA_character_, API_Authors = NA_character_,
    API_Year = NA_integer_, API_Publisher = NA_character_,
    API_ISBN13 = NA_character_, stringsAsFactors = FALSE
  )

  if (!nzchar(api_key)) {
    empty$API_Status <- "API key missing"
    return(empty)
  }

  response <- tryCatch(
    GET(
      paste0("https://www.googleapis.com/books/v1/volumes/", id),
      query = list(key = api_key),
      timeout(20)
    ),
    error = function(e) NULL
  )

  if (is.null(response)) return(empty)
  empty$HTTP_Status <- status_code(response)
  if (status_code(response) != 200) {
    empty$API_Status <- paste("HTTP error", status_code(response))
    return(empty)
  }

  result <- tryCatch(content(response, "parsed"), error = function(e) NULL)
  if (is.null(result) || is.null(result$volumeInfo)) {
    empty$API_Status <- "Invalid response"
    return(empty)
  }

  info <- result$volumeInfo
  ids <- info$industryIdentifiers
  isbn13 <- NA_character_
  if (!is.null(ids)) {
    for (identifier in ids) {
      if (identical(identifier$type, "ISBN_13")) {
        isbn13 <- as.character(identifier$identifier)
        break
      }
    }
  }

  value_or_na <- function(x) if (is.null(x) || length(x) == 0) NA_character_ else as.character(x[[1]])
  year_text <- value_or_na(info$publishedDate)
  year <- if (is.na(year_text)) NA_integer_ else suppressWarnings(as.integer(substr(year_text, 1, 4)))

  empty$API_Status <- "Found"
  empty$API_Title <- value_or_na(info$title)
  empty$API_Authors <- if (is.null(info$authors)) NA_character_ else paste(unlist(info$authors), collapse = "; ")
  empty$API_Year <- year
  empty$API_Publisher <- value_or_na(info$publisher)
  empty$API_ISBN13 <- isbn13
  empty
}

# Match records by ISBN, not by the position of the rows.
original <- html_data
original$ISBN <- as.character(original$ISBN)
lookup_rows <- match(original$ISBN, book_lookup$ISBN)
if (anyNA(lookup_rows)) stop("An ISBN is missing from book_lookup.")

api_results <- do.call(rbind, lapply(seq_len(nrow(original)), function(i) {
  get_google_book(original$ISBN[i], book_lookup$Google_Books_ID[lookup_rows[i]])
}))

# Exact comparisons: author/publisher variations are shown separately.
api_results$Title_Match <- !is.na(api_results$API_Title) &
  api_results$API_Title == original$Title
api_results$Year_Match <- !is.na(api_results$API_Year) &
  api_results$API_Year == original$Year
api_results$ISBN_Match <- !is.na(api_results$API_ISBN13) &
  api_results$API_ISBN13 == original$ISBN

knitr::kable(
  api_results[, c("ISBN", "Google_Books_ID", "HTTP_Status", "API_Status",
                  "Title_Match", "Year_Match", "ISBN_Match")],
  col.names = c("ISBN", "Google Books ID", "HTTP Status", "API Status",
                "Title Match", "Publication Year Match", "ISBN Match"),
  row.names = FALSE,
  caption = "Google Books API Validation Results"
)
Google Books API Validation Results
ISBN Google Books ID HTTP Status API Status Title Match Publication Year Match ISBN Match
9780070612938 NBIoAQAAMAAJ 200 Found TRUE TRUE TRUE
9781133386681 XScJAAAAQBAJ 200 Found TRUE TRUE TRUE
9780984543809 s_IbSQAACAAJ 200 Found TRUE TRUE TRUE
Code
# These fields need manual review because of abbreviations and initials.
knitr::kable(
  data.frame(
    ISBN = original$ISBN,
    Original_Authors = original$Authors,
    API_Authors = api_results$API_Authors,
    Original_Publisher = original$Publisher,
    API_Publisher = api_results$API_Publisher
  ),
  col.names = c("ISBN-13", "Original Authors", "Google Books Authors",
                "Original Publisher", "Google Books Publisher"),
  row.names = FALSE,
  caption = "Author and Publisher Comparison"
)
Author and Publisher Comparison
ISBN-13 Original Authors Google Books Authors Original Publisher Google Books Publisher
9780070612938 John J. Grainger; William D. Stevenson Jr. John Grainger; William D. Stevenson McGraw-Hill McGraw-Hill Education
9781133386681 J. Duncan Glover; Mulukutla S. Sarma; Thomas J. Overbye J. Duncan Glover; Mulukutla S. Sarma; Thomas Overbye Cengage Learning Cengage Learning
9780984543809 Hadi Saadat Hadi Saadat PSA Publishing PSA Pub.

11.5.2.1 API Validation Discussion

I first tried searching Google Books by ISBN, but the search endpoint returned HTTP errors or no results. I then used the Google Books IDs to retrieve the three records directly.

In the RStudio console test, all three direct requests returned HTTP 200. The titles, publication years, and ISBN-13 numbers matched my dataset. The API used shorter versions of some author and publisher names. I kept the original values and showed these differences for review.

The tables above show the results of the current Render. If an API request fails during Render, the table records the error instead of treating the book as verified.

11.6 Results and Discussion

The HTML and JSON files were successfully imported into R. Both datasets contained three books and five variables. The identical() function returned TRUE, confirming that both datasets contained the same information. No missing values were found.

All three ISBN numbers passed the check-digit validation. During the final report execution, the Google Books API returned HTTP 200 for all three records. The book titles, publication years, and ISBN numbers matched the original dataset. Some differences were found in the author and publisher names because the API used shorter names or abbreviations. These differences were included in a separate table for manual review.

11.7 Conclusions

In this project, I organized information from three electrical engineering books in HTML and JSON files. I imported both files into R and confirmed that they contain the same information.

I also checked missing values and validated the ISBN-13 numbers. Google Books helped me compare the titles, publication years, and ISBN numbers with external records. I learned that author and publisher names can be written differently, even when the ISBN matches.

This project helped me understand data consistency, local validation, and external API validation. It also showed me why API errors should be reported separately from data errors.

12 AI Use

ChatGPT was used to help interpret the assignment requirements, organize the planned approach, improve the English writing, and provide guidance for the HTML, JSON, and R workflow. I selected the electrical engineering topic based on my professional background and reviewed the bibliographic information, data transformations, and reported results.

13 References

Grainger, J. J., & Stevenson, W. D., Jr. (1994). Power System Analysis. McGraw-Hill.

Glover, J. D., Sarma, M. S., & Overbye, T. J. (2012). Power System Analysis & Design, SI Version. Cengage Learning.

Saadat, H. (2010). Power System Analysis (3rd ed.). PSA Publishing.

Google Books API. https://developers.google.com/books