From e95de40fb57c1005f7fb1b1de25b3a0d0f8e2e93 Mon Sep 17 00:00:00 2001 From: HamdiSaidaniX Date: Wed, 24 Dec 2025 16:13:56 +0100 Subject: [PATCH 1/3] Create xml-to-json.tsxfeat: Add XML to JSON converter --- pages/utilities/xml-to-json.tsx | 1 + 1 file changed, 1 insertion(+) create mode 100644 pages/utilities/xml-to-json.tsx diff --git a/pages/utilities/xml-to-json.tsx b/pages/utilities/xml-to-json.tsx new file mode 100644 index 0000000..9f6527e --- /dev/null +++ b/pages/utilities/xml-to-json.tsx @@ -0,0 +1 @@ +// XML to JSON Converter - Full content to be added From b8fb029ab103ad2b908982cd1c3f81793e1a446a Mon Sep 17 00:00:00 2001 From: HamdiSaidaniX Date: Wed, 24 Dec 2025 16:21:18 +0100 Subject: [PATCH 2/3] Update xml-to-json.tsx --- pages/utilities/xml-to-json.tsx | 103 +++++++++++++++++++++++++++++++- 1 file changed, 102 insertions(+), 1 deletion(-) diff --git a/pages/utilities/xml-to-json.tsx b/pages/utilities/xml-to-json.tsx index 9f6527e..d2eafa9 100644 --- a/pages/utilities/xml-to-json.tsx +++ b/pages/utilities/xml-to-json.tsx @@ -1 +1,102 @@ -// XML to JSON Converter - Full content to be added +import { useCallback, useState } from "react"; +import { Textarea } from "@/components/ds/TextareaComponent"; +import PageHeader from "@/components/PageHeader"; +import { Card } from "@/components/ds/CardComponent"; +import { Button } from "@/components/ds/ButtonComponent"; +import { Label } from "@/components/ds/LabelComponent"; +import Header from "@/components/Header"; +import { useCopyToClipboard } from "@/components/hooks/useCopyToClipboard"; +import { CMDK } from "@/components/CMDK"; +import CallToActionGrid from "@/components/CallToActionGrid"; +import XmlToJsonSEO from "@/components/seo/XmlToJsonSEO"; +import Meta from "../../components/Meta"; + +function xmlToJson(xml: string): unknown { + const parser = new DOMParser(); + const doc = parser.parseFromString(xml, "text/xml"); + const parserError = doc.querySelector("parsererror"); + if (parserError) throw new Error("Invalid XML"); + + function nodeToJson(node: Node): unknown { + const obj: Record = {}; + if (node.nodeType === Node.ELEMENT_NODE) { + const element = node as Element; + if (element.attributes.length > 0) { + obj["@attributes"] = {}; + for (let i = 0; i < element.attributes.length; i++) { + const attr = element.attributes[i]; + (obj["@attributes"] as Record)[attr.nodeName] = attr.nodeValue || ""; + } + } + if (element.hasChildNodes()) { + for (let i = 0; i < element.childNodes.length; i++) { + const child = element.childNodes[i]; + if (child.nodeType === Node.TEXT_NODE || child.nodeType === Node.CDATA_SECTION_NODE) { + const text = child.textContent?.trim(); + if (text) { + if (element.childNodes.length === 1 && element.attributes.length === 0) return text; + obj["#text"] = text; + } + } else if (child.nodeType === Node.ELEMENT_NODE) { + const childName = child.nodeName; + const childValue = nodeToJson(child); + if (obj[childName] !== undefined) { + if (!Array.isArray(obj[childName])) obj[childName] = [obj[childName]]; + (obj[childName] as unknown[]).push(childValue); + } else { + obj[childName] = childValue; + } + } + } + } + if (Object.keys(obj).length === 0) return null; + } + return obj; + } + const root = doc.documentElement; + return { [root.nodeName]: nodeToJson(root) }; +} + +export default function XMLtoJSON() { + const [input, setInput] = useState(""); + const [output, setOutput] = useState(""); + const { buttonText, handleCopy } = useCopyToClipboard(); + + const handleChange = useCallback((event: React.ChangeEvent) => { + const { value } = event.currentTarget; + setInput(value); + if (!value.trim()) { setOutput(""); return; } + try { + const jsonObject = xmlToJson(value.trim()); + setOutput(JSON.stringify(jsonObject, null, 2)); + } catch { + setOutput("Invalid XML input"); + } + }, []); + + return ( +
+ +
+ +
+ +
+
+ +
+ +