Skip to content

Instantly share code, notes, and snippets.

@Normal-Tangerine8609
Last active September 5, 2025 19:19
Show Gist options
  • Select an option

  • Save Normal-Tangerine8609/d9532d78c9a3afa31899b00e21feb45d to your computer and use it in GitHub Desktop.

Select an option

Save Normal-Tangerine8609/d9532d78c9a3afa31899b00e21feb45d to your computer and use it in GitHub Desktop.

Revisions

  1. Normal-Tangerine8609 revised this gist Sep 21, 2022. 1 changed file with 12 additions and 12 deletions.
    24 changes: 12 additions & 12 deletions rss.js
    Original file line number Diff line number Diff line change
    @@ -29,10 +29,7 @@ function parseXML(string) {
    * }
    *
    */

    // Declare the parser
    let parser = new XMLParser(string)


    // Root of xml
    let main = {
    isRoot: true,
    @@ -45,10 +42,13 @@ function parseXML(string) {

    // Store symbols to go back to parent nodes
    let goBack = {}

    // Declare the parser
    let parser = new XMLParser(string)

    // Store the new node and switch targets when entering a new tag
    parser.didStartElement = (name, attrs) => {
    let backTo = Symbol("unique")
    let backTo = Symbol()
    goBack[backTo] = target
    let newTarget = {
    name,
    @@ -61,19 +61,19 @@ function parseXML(string) {
    target = newTarget
    }

    // Add the inner text to the node, if there are multiple text nodes, combine them with spaces
    parser.foundCharacters = (text) => {
    target.innerText +=
    target.innerText === "" ? text.trim() : " " + text.trim()
    }

    // Go back to the parent node when entering a closing tag
    parser.didEndElement = (name) => {
    let sym = target.end
    delete target.end
    target = goBack[sym]
    }

    // Add the inner text to the node, if there are multiple text nodes, combine them with spaces
    parser.foundCharacters = (text) => {
    target.innerText +=
    target.innerText === "" ? text.trim() : " " + text.trim()
    }

    // Throw error on invalid input
    parser.parseErrorOccurred = () => {
    console.warn(
    @@ -93,7 +93,7 @@ function parseXML(string) {

    // Remove the isRoot key
    delete main.isRoot

    /*
    * Part 2
    *
  2. Normal-Tangerine8609 revised this gist Jul 31, 2022. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion rss.js
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@ function parseXML(string) {
    /*
    * Part 1
    *
    * Parse the xml into a AST-like json
    * Parse the xml into a DOM-like json
    *
    * Input: <tag attribute="value">text node<inline>text node</inline>text node</tag>
    *
  3. Normal-Tangerine8609 revised this gist Jun 7, 2022. No changes.
  4. Normal-Tangerine8609 created this gist Jun 7, 2022.
    170 changes: 170 additions & 0 deletions rss.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,170 @@
    function parseXML(string) {
    /*
    * Part 1
    *
    * Parse the xml into a AST-like json
    *
    * Input: <tag attribute="value">text node<inline>text node</inline>text node</tag>
    *
    * Output:
    * {
    * "name": "root",
    * "children": [
    * {
    * "name": "tag",
    * "attrs": {
    * "attribute": "value"
    * },
    * "innerText": "text node text node",
    * "children": [
    * {
    * "name": "inline",
    * "attrs": {},
    * "innerText": "text node",
    * "children": []
    * }
    * ]
    * }
    * ]
    * }
    *
    */

    // Declare the parser
    let parser = new XMLParser(string)

    // Root of xml
    let main = {
    isRoot: true,
    name: "root",
    children: []
    }

    // Node to add onto
    let target = main

    // Store symbols to go back to parent nodes
    let goBack = {}

    // Store the new node and switch targets when entering a new tag
    parser.didStartElement = (name, attrs) => {
    let backTo = Symbol("unique")
    goBack[backTo] = target
    let newTarget = {
    name,
    attrs,
    innerText: "",
    children: [],
    end: backTo
    }
    target.children.push(newTarget)
    target = newTarget
    }

    // Add the inner text to the node, if there are multiple text nodes, combine them with spaces
    parser.foundCharacters = (text) => {
    target.innerText +=
    target.innerText === "" ? text.trim() : " " + text.trim()
    }

    // Go back to the parent node when entering a closing tag
    parser.didEndElement = (name) => {
    let sym = target.end
    delete target.end
    target = goBack[sym]
    }

    // Throw error on invalid input
    parser.parseErrorOccurred = () => {
    console.warn(
    "A parse error occurred, ensure the document is formatted properly."
    )
    }

    // Parse and return the root
    parser.parse()

    // If something went wrong and there is no root node, throw an error
    if (!main.isRoot) {
    console.warn(
    "A parse error occurred, ensure the document is formatted properly."
    )
    }

    // Remove the isRoot key
    delete main.isRoot

    /*
    * Part 2
    *
    * Manipulate the AST-like json into a simpler json without attributes and other less important items. This will not collect both tag and text nodes if they are in the same tag.
    *
    * Input:
    * {
    * "name": "root",
    * "children": [
    * {
    * "name": "tag",
    * "attrs": {
    * "attribute": "value"
    * },
    * "innerText": "text node text node",
    * "children": [
    * {
    * "name": "inline",
    * "attrs": {},
    * "innerText": "text node",
    * "children": []
    * }
    * ]
    * }
    * ]
    * }
    *
    * Output:
    * {
    * "tag": {
    * "inline": "text node"
    * }
    * }
    *
    * Notes: you can chose to only use part 1 if you need the attributes or text and tag nodes in the same tag. Replace the `return traverse(main)` below to `return main`
    */

    // Return the new simple JSON
    return traverse(main)

    // Function to change each node
    function traverse(node) {
    // Store the new node
    let newNode = {}

    // Repeat with all children nodes
    for (let child of node.children) {
    // traverse the child
    let newChild = traverse(child)

    // If there are no children of the child than it should become a text value
    if (child.children.length === 0) {
    newChild = child.innerText
    }

    // If the new node already has a key of the child's name it will become an array
    if (newNode[child.name]) {
    // If it is an array, push the new child
    if (Array.isArray(newNode[child.name])) {
    newNode[child.name].push(newChild)
    } else {
    // If it is not an array, change it into one
    newNode[child.name] = [newNode[child.name], newChild]
    }
    } else {
    // If it is not in the keys, set the child as a value in the new node
    newNode[child.name] = newChild
    }
    }

    // Return the new node
    return newNode
    }
    }