I’m making a web app with ReactJS that uses the BoardGameGeek API. This API returns XML files, so I have been converting them into JSON and then parsing them. In some cases, the JSON object works perfectly, like when I render <pre>{JSON.stringify(xmlData, null, 4)}</pre>
, where xmlData
is the JSON object. However, when I try to access a specific element with console.log(xmlData?.items.item[i].name._value)
, I only get undefined
. The thing that is really confusing to me is that there are no issues in another file with seemingly the exact same methodology for parsing XML.
Here is the file that doesn’t work properly:
"use client";
import { useEffect, useState } from "react";
import { Root, Items } from "./searchInterfaces";
import { FormControl, InputLabel, Select } from "@mui/material";
import xmlJs from "xml-js";
interface SelectProps {
search: string;
clicked: boolean;
}
export default function GameSelect(selectProp: SelectProps) {
const [xmlData, setXmlData] = useState<Root>();
useEffect(() => {
// Define the API URL
if (selectProp.clicked) {
const apiUrl =
"https://api.geekdo.com/xmlapi2/search?query=" + selectProp.search;
fetch(apiUrl)
.then((response) => response.text())
.then((xmlText) => {
setXmlData(
JSON.parse(
xmlJs.xml2json(xmlText, {
compact: true,
spaces: 2,
})
)
);
addElements();
})
.catch((error) => {
console.error("Error fetching XML data:", error);
});
}
}, [selectProp.search, selectProp.clicked]);
const addElements = () => {
if (selectProp.clicked) {
var select = document.getElementById("select") as any;
if (select) {
for (let i = 0; i < Number(xmlData?.items._total); i++) {
console.log(xmlData?.items.item[i].name._value);
select.options[select.options.length] = new Option(
xmlData?.items.item[i].name._value + ""
);
}
}
}
};
return (
<>
<FormControl fullWidth>
<InputLabel>Game</InputLabel>
<Select id="select" className="select" label="game" defaultValue={""} />
</FormControl>
</>
);
}
The file where it works is here:
"use client";
import { useEffect, useState } from "react";
import { Welcome } from "./idInterfaces";
import "./page.css";
import xmlJs from "xml-js";
interface GameProps {
id: string;
clicked: boolean;
}
export default function GameBox(gameProp: GameProps) {
const [xmlData, setXmlData] = useState<Welcome>();
useEffect(() => {
// Define the API URL
if (gameProp.clicked) {
const apiUrl = "https://api.geekdo.com/xmlapi2/thing?id=" + gameProp.id;
fetch(apiUrl)
.then((response) => response.text())
.then((xmlText) => {
setXmlData(
JSON.parse(
xmlJs.xml2json(xmlText, {
compact: true,
spaces: 2,
})
)
);
})
.catch((error) => {
console.error("Error fetching XML data:", error);
});
}
}, [gameProp.id, gameProp.clicked]);
try {
return (
<div style={{ marginTop: "15px" }}>
{gameProp.clicked ? (
xmlData ? (
<div>
<p>Name: {xmlData.items.item.name[0]._attributes.value}</p>
<p>ID: {xmlData.items.item._attributes.id}</p>
<p>
Year Released:{" "}
{xmlData.items.item.yearpublished._attributes.value}
</p>
</div>
) : (
<p>Loading XML data...</p>
)
) : (
<p></p>
)}
</div>
);
} catch (e) {
if (
e ==
"TypeError: Cannot read properties of undefined (reading '_attributes')"
) {
e = "Please enter a valid ID.";
}
return (
<div>
<p>{String(e)}</p>
</div>
);
}
}
I’ve spent a good bit of time investigating in the Chrome debugger, but to no avail. I’m not familiar with unit testing in React, so I haven’t done that yet but I hope I found the equivalent with an absurd amount of console.log()
statements.
If there’s anything else that doesn’t make sense, please let me know. I tried to craft a well-rounded question but some things may have fallen through.
Thanks!