diff --git a/__tests__/xml-to-json.test.ts b/__tests__/xml-to-json.test.ts new file mode 100644 index 0000000..7097499 --- /dev/null +++ b/__tests__/xml-to-json.test.ts @@ -0,0 +1,144 @@ +/** + * @jest-environment jsdom + */ +import { xmlToJson } from "../lib/xmlToJson"; + +describe("XML to JSON Converter", () => { + describe("Basic conversion", () => { + it("should convert simple XML to JSON", () => { + const xml = "test"; + const result = xmlToJson(xml); + expect(result).toEqual({ root: { name: "test" } }); + }); + + it("should handle nested elements", () => { + const xml = "value"; + const result = xmlToJson(xml); + expect(result).toEqual({ + root: { parent: { child: "value" } }, + }); + }); + + it("should handle empty elements", () => { + const xml = ""; + const result = xmlToJson(xml); + expect(result).toEqual({ root: { empty: null } }); + }); + }); + + describe("Attribute handling", () => { + it("should convert XML attributes to @attributes object", () => { + const xml = 'test'; + const result = xmlToJson(xml); + expect(result).toEqual({ + root: { "@attributes": { id: "123" }, name: "test" }, + }); + }); + + it("should handle multiple attributes", () => { + const xml = ''; + const result = xmlToJson(xml); + expect(result).toEqual({ + root: { + "@attributes": { id: "123", class: "main", "data-test": "true" }, + }, + }); + }); + + it("should handle element with only attributes", () => { + const xml = ''; + const result = xmlToJson(xml); + expect(result).toEqual({ + root: { "@attributes": { id: "123" } }, + }); + }); + }); + + describe("Array handling", () => { + it("should convert multiple same-named elements to array", () => { + const xml = "123"; + const result = xmlToJson(xml); + expect(result).toEqual({ root: { item: ["1", "2", "3"] } }); + }); + + it("should handle mixed elements with arrays", () => { + const xml = + "test12"; + const result = xmlToJson(xml); + expect(result).toEqual({ + root: { name: "test", item: ["1", "2"] }, + }); + }); + }); + + describe("Text content handling", () => { + it("should handle text content with attributes", () => { + const xml = 'text content'; + const result = xmlToJson(xml); + expect(result).toEqual({ + root: { "@attributes": { id: "1" }, "#text": "text content" }, + }); + }); + + it("should trim whitespace from text content", () => { + const xml = " test "; + const result = xmlToJson(xml); + expect(result).toEqual({ root: { name: "test" } }); + }); + }); + + describe("Error handling", () => { + it("should throw error for invalid XML", () => { + const xml = ""; + expect(() => xmlToJson(xml)).toThrow("Invalid XML"); + }); + + it("should throw error for malformed XML", () => { + const xml = "not xml at all"; + expect(() => xmlToJson(xml)).toThrow("Invalid XML"); + }); + }); + + describe("Complex XML structures", () => { + it("should handle deeply nested structures", () => { + const xml = + "deep"; + const result = xmlToJson(xml); + expect(result).toEqual({ + root: { level1: { level2: { level3: "deep" } } }, + }); + }); + + it("should handle real-world XML example", () => { + const xml = ` + + + John + john@example.com + + + Jane + jane@example.com + + + `; + const result = xmlToJson(xml); + expect(result).toEqual({ + users: { + user: [ + { + "@attributes": { id: "1" }, + name: "John", + email: "john@example.com", + }, + { + "@attributes": { id: "2" }, + name: "Jane", + email: "jane@example.com", + }, + ], + }, + }); + }); + }); +}); diff --git a/components/seo/MarkdownToHtmlSEO.tsx b/components/seo/MarkdownToHtmlSEO.tsx new file mode 100644 index 0000000..e70ae6f --- /dev/null +++ b/components/seo/MarkdownToHtmlSEO.tsx @@ -0,0 +1,150 @@ +import Link from "next/link"; + +export default function MarkdownToHtmlSEO() { + return ( +
+
+

+ This free tool quickly converts Markdown to HTML. Ideal for blog + posts, documentation, README files, or web content. Just paste your + Markdown and get clean HTML code. Built with 💜 by the Jam developers. +

+
+ +
+

How to Use the Markdown to HTML Converter

+

+ To convert Markdown to HTML, simply paste your Markdown content in the + input field and the HTML output will appear instantly. No signup + required. +

+

+ Our converter supports all standard Markdown syntax including headers, + bold, italic, links, images, code blocks, lists, and more. +

+

+ Need to work with other formats? Check out our{" "} + JSON Formatter or{" "} + XML to JSON converter. +

+
+ +
+

Supported Markdown Syntax

+
    +
  • + Headers:
    Use # for h1, ## for h2, up to ###### for h6. +
  • +
  • + Bold & Italic:
    Use **text** or __text__ for bold, + *text* or _text_ for italic. +
  • +
  • + Links:
    Use [link text](url) to create hyperlinks. +
  • +
  • + Images:
    Use ![alt text](image-url) to embed images. +
  • +
  • + Code:
    Use `inline code` or triple backticks for code + blocks with syntax highlighting. +
  • +
  • + Lists:
    Use - or * for unordered lists, numbers for + ordered lists. +
  • +
  • + Blockquotes:
    Use > at the start of a line for + quotes. +
  • +
+
+ +
+

Benefits of Converting Markdown to HTML

+

+ Markdown is a lightweight markup language that's easy to write and + read. HTML (HyperText Markup Language) is the standard language for + creating web pages. +

+
    +
  • + Web Publishing:
    Convert your Markdown documentation or + blog posts directly to HTML for web publishing. +
  • +
  • + Email Content:
    Transform Markdown into HTML for rich + email content that displays correctly in all email clients. +
  • +
  • + Documentation:
    Convert README files and documentation + written in Markdown to HTML for hosting on websites. +
  • +
  • + Content Management:
    Many CMS platforms accept HTML + input, making this converter useful for content migration. +
  • +
+
+ +
+

Markdown vs HTML: When to Use Each

+
    +
  • + Writing Speed:
    Markdown is faster to write and more + readable in its raw form. HTML offers more control over formatting + and layout. +
  • +
  • + Portability:
    Markdown files are plain text and work + anywhere. HTML requires a browser or renderer to display properly. +
  • +
  • + Features:
    HTML supports advanced features like forms, + tables with styling, and interactive elements. Markdown is simpler + but covers most common formatting needs. +
  • +
  • + Use Cases:
    Markdown is perfect for documentation, + README files, and notes. HTML is essential for web pages and + applications. +
  • +
+
+ +
+

FAQs

+
    +
  • + Can you convert Markdown to HTML?
    Yes, our tool + instantly converts Markdown syntax to valid HTML code that you can + use on any website. +
  • +
  • + Is this converter free to use?
    Yes, this Markdown to + HTML converter is completely free, open source, and has no ads. +
  • +
  • + Does the converter support code syntax highlighting?
    {" "} + Yes, fenced code blocks with language specification are converted to + HTML with appropriate class names for syntax highlighting. +
  • +
  • + Is my data secure?
    Absolutely. All conversion happens + in your browser. Your data never leaves your device. +
  • +
  • + What Markdown flavors are supported?
    Our converter + supports standard Markdown syntax including GitHub Flavored Markdown + features like task lists and strikethrough. +
  • +
  • + Can I use this for large documents?
    Yes, the converter + handles documents of any size efficiently since all processing is + done client-side. +
  • +
+
+
+ ); +} diff --git a/components/seo/XmlToJsonSEO.tsx b/components/seo/XmlToJsonSEO.tsx new file mode 100644 index 0000000..29832f6 --- /dev/null +++ b/components/seo/XmlToJsonSEO.tsx @@ -0,0 +1,182 @@ +import Link from "next/link"; + +export default function XmlToJsonSEO() { + return ( +
+
+

+ Our free, open-source, and ad-free XML to JSON converter makes it + easy to transform your data formats. Convert configuration files, + API responses, or legacy XML data into modern JSON with just a few + clicks. Built with 💜 for developers by developers. +

+

+ Looking for YAML conversion instead? Check out{" "} + + jsontoyamlconverter.com + {" "} + for JSON ↔ YAML conversions. +

+
+ +
+

Why Convert XML to JSON?

+

+ XML (eXtensible Markup Language) has been a standard for data + exchange for decades, but JSON (JavaScript Object Notation) has + become the preferred format for modern web development. Converting{" "} + XML to JSON is essential when you need: +

+
    +
  • + Modern API Integration:
    Most modern REST APIs use + JSON, making conversion essential for integrating legacy XML data. +
  • +
  • + Reduced Data Size:
    JSON is more compact than XML, + reducing bandwidth and improving performance. +
  • +
  • + JavaScript Compatibility:
    JSON is native to + JavaScript, making it easier to work with in web applications. +
  • +
  • + Better Readability:
    JSON's simpler syntax makes data + easier to read and understand compared to verbose XML. +
  • +
+
+ +
+

How to Use Our XML to JSON Converter

+

Converting XML data to JSON has never been easier:

+
    +
  • + Step 1:
    Paste your XML code into the input box. +
  • +
  • + Step 2:
    Instantly receive your JSON output. No + registration or ads. +
  • +
  • + Step 3:
    Copy your JSON data and integrate it into + your project. +
  • +
+
+ +
+

Key Features of Our XML to JSON Tool

+
    +
  • + Client-side processing
    Your data never leaves your + browser - complete privacy guaranteed. +
  • +
  • + Attribute handling
    XML attributes are preserved as + @attributes in the JSON output. +
  • +
  • + Array detection
    Multiple elements with the same name + are automatically converted to arrays. +
  • +
  • + CDATA support
    CDATA sections are properly extracted + as text content. +
  • +
  • + Error detection
    Invalid XML is detected and reported + immediately. +
  • +
+
+ +
+

XML vs JSON: When to Use Each

+

+ Both XML and JSON have their strengths. Here's when to use each: +

+
    +
  • + XML:
    + Better for documents with mixed content, complex schemas, XSLT + transformations, and SOAP web services. +
  • +
  • + JSON:
    Preferred for REST APIs, configuration files, + web applications, and when file size matters. +
  • +
+
+ +
+

FAQs

+
    +
  • + What is XML?
    XML (eXtensible Markup Language) is a + markup language that defines rules for encoding documents in a + format that is both human-readable and machine-readable. +
  • +
  • + What is JSON?
    JSON (JavaScript Object Notation) is a + lightweight data format used to transmit data between servers and + web applications. +
  • +
  • + How are XML attributes handled?
    XML attributes are + converted to an @attributes object in the JSON output, preserving + all attribute data. +
  • +
  • + Can I convert JSON back to XML?
    While more complex + due to attribute handling, you can manually restructure JSON back + to XML format. +
  • +
  • + Is my data secure?
    Yes! All processing happens in + your browser. Your XML data is never sent to any server. +
  • +
  • + Need YAML conversion?
    For JSON to YAML conversion, + visit{" "} + + jsontoyamlconverter.com + + . +
  • +
+
+ +
+

Related Tools

+

Check out our other data conversion utilities:

+
    +
  • + JSON Formatter - + Format and beautify JSON data +
  • +
  • + YAML to JSON - Convert + YAML to JSON format +
  • +
  • + JSON to YAML - Convert + JSON to YAML format +
  • +
  • + CSV to JSON - Convert + CSV to JSON format +
  • +
+
+
+ ); +} diff --git a/components/utils/tools-list.ts b/components/utils/tools-list.ts index e4c3ada..e30f7c9 100644 --- a/components/utils/tools-list.ts +++ b/components/utils/tools-list.ts @@ -161,4 +161,16 @@ export const tools = [ "Generate cryptographically secure random strings with configurable character sets. Perfect for API keys, tokens, passwords, and secure identifiers.", link: "/utilities/random-string-generator", }, + { + title: "XML to JSON", + description: + "Convert XML data to JSON format instantly. Perfect for transforming XML APIs, configuration files, and data feeds into JSON for modern web applications.", + link: "/utilities/xml-to-json", + }, + { + title: "Markdown to HTML", + description: + "Convert Markdown to HTML format quickly and easily. Perfect for blog posts, documentation, README files, and web content. Supports all standard Markdown syntax.", + link: "/utilities/markdown-to-html", + }, ]; diff --git a/lib/markdownToHtml.ts b/lib/markdownToHtml.ts new file mode 100644 index 0000000..e4298c7 --- /dev/null +++ b/lib/markdownToHtml.ts @@ -0,0 +1,127 @@ +/** + * Converts Markdown string to HTML + * @param markdown - The Markdown string to convert + * @returns The converted HTML string + */ +export function markdownToHtml(markdown: string): string { + if (!markdown.trim()) { + return ""; + } + + let html = markdown; + + // Escape HTML entities first (except for what we'll convert) + html = html + .replace(/&/g, "&") + .replace(//g, ">"); + + // Code blocks (fenced with ```) - must be processed before inline code + html = html.replace( + /```(\w*)\n([\s\S]*?)```/g, + (_match, language, code) => { + const langClass = language ? ` class="language-${language}"` : ""; + return `
${code.trim()}
`; + } + ); + + // Inline code (single backticks) + html = html.replace(/`([^`]+)`/g, "$1"); + + // Headers (h1-h6) + html = html.replace(/^###### (.+)$/gm, "
$1
"); + html = html.replace(/^##### (.+)$/gm, "
$1
"); + html = html.replace(/^#### (.+)$/gm, "

$1

"); + html = html.replace(/^### (.+)$/gm, "

$1

"); + html = html.replace(/^## (.+)$/gm, "

$1

"); + html = html.replace(/^# (.+)$/gm, "

$1

"); + + // Horizontal rule + html = html.replace(/^(-{3,}|\*{3,}|_{3,})$/gm, "
"); + + // Bold and italic combinations + html = html.replace(/\*\*\*(.+?)\*\*\*/g, "$1"); + html = html.replace(/___(.+?)___/g, "$1"); + + // Bold + html = html.replace(/\*\*(.+?)\*\*/g, "$1"); + html = html.replace(/__(.+?)__/g, "$1"); + + // Italic + html = html.replace(/\*(.+?)\*/g, "$1"); + html = html.replace(/_(.+?)_/g, "$1"); + + // Strikethrough + html = html.replace(/~~(.+?)~~/g, "$1"); + + // Blockquotes + html = html.replace(/^> (.+)$/gm, "
$1
"); + // Merge consecutive blockquotes + html = html.replace(/<\/blockquote>\n
/g, "\n"); + + // Unordered lists + html = html.replace(/^[*\-+] (.+)$/gm, "
  • $1
  • "); + html = html.replace(/(
  • .*<\/li>\n?)+/g, (match) => `
      \n${match}
    \n`); + + // Ordered lists + html = html.replace(/^\d+\. (.+)$/gm, "
  • $1
  • "); + html = html.replace( + /(
  • .*<\/li>\n?)(?=
  • |\n|$)/g, + (match, _, offset, string) => { + // Check if this is part of an ordered list context + const before = string.substring(0, offset); + if (before.match(/\d+\. [^\n]+\n?$/)) { + return match; + } + return match; + } + ); + + // Links: [text](url) + html = html.replace( + /\[([^\]]+)\]\(([^)]+)\)/g, + '$1' + ); + + // Images: ![alt](url) + html = html.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, '$1'); + + // Task lists + html = html.replace( + /
  • \[x\] (.+)<\/li>/gi, + '
  • $1
  • ' + ); + html = html.replace( + /
  • \[ \] (.+)<\/li>/g, + '
  • $1
  • ' + ); + + // Paragraphs (double newlines) + const lines = html.split(/\n\n+/); + html = lines + .map((line) => { + const trimmed = line.trim(); + // Skip if already wrapped in block element + if ( + trimmed.startsWith("${trimmed}

    `; + }) + .join("\n\n"); + + // Clean up extra newlines within paragraphs + html = html.replace(/

    ([\s\S]*?)<\/p>/g, (_match, content) => { + return `

    ${content.replace(/\n/g, "
    ")}

    `; + }); + + return html.trim(); +} diff --git a/lib/xmlToJson.ts b/lib/xmlToJson.ts new file mode 100644 index 0000000..bf34107 --- /dev/null +++ b/lib/xmlToJson.ts @@ -0,0 +1,85 @@ +/** + * Converts XML string to JSON object + * @param xml - The XML string to convert + * @returns The parsed JSON object + */ +export function xmlToJson(xml: string): unknown { + const parser = new DOMParser(); + const doc = parser.parseFromString(xml, "text/xml"); + + // Check for parsing errors + const parserError = doc.querySelector("parsererror"); + if (parserError) { + throw new Error("Invalid XML"); + } + + function nodeToJson(node: Node): unknown { + const obj: Record = {}; + + // Handle element nodes + if (node.nodeType === Node.ELEMENT_NODE) { + const element = node as Element; + + // Add attributes + 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 || ""; + } + } + + // Handle child nodes + if (element.hasChildNodes()) { + for (let i = 0; i < element.childNodes.length; i++) { + const child = element.childNodes[i]; + + // Text node + if ( + child.nodeType === Node.TEXT_NODE || + child.nodeType === Node.CDATA_SECTION_NODE + ) { + const text = child.textContent?.trim(); + if (text) { + // If only text content, return it directly + if ( + element.childNodes.length === 1 && + element.attributes.length === 0 + ) { + return text; + } + obj["#text"] = text; + } + } + // Element node + else if (child.nodeType === Node.ELEMENT_NODE) { + const childName = child.nodeName; + const childValue = nodeToJson(child); + + // Handle arrays (multiple elements with same name) + 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 has only @attributes, merge them + const keys = Object.keys(obj); + if (keys.length === 0) { + return null; + } + } + + return obj; + } + + const root = doc.documentElement; + return { [root.nodeName]: nodeToJson(root) }; +} diff --git a/pages/utilities/markdown-to-html.tsx b/pages/utilities/markdown-to-html.tsx new file mode 100644 index 0000000..a280b4a --- /dev/null +++ b/pages/utilities/markdown-to-html.tsx @@ -0,0 +1,78 @@ +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 Meta from "@/components/Meta"; +import MarkdownToHtmlSEO from "@/components/seo/MarkdownToHtmlSEO"; +import { markdownToHtml } from "@/lib/markdownToHtml"; + +export default function MarkdownToHTML() { + const [input, setInput] = useState(""); + const [output, setOutput] = useState(""); + const { buttonText, handleCopy } = useCopyToClipboard(); + + const handleChange = useCallback( + (event: React.ChangeEvent) => { + const { value } = event.currentTarget; + setInput(value); + + try { + const htmlOutput = markdownToHtml(value); + setOutput(htmlOutput); + } catch { + setOutput("Invalid Markdown"); + } + }, + [] + ); + + return ( +
    + +
    + + +
    + +
    + +
    + +
    + +