Retrieve information from an XML document

I have some XML content that looks like this:

<Artificial name="Artifical name">
    <Machine>
        <MachineEnvironment uri="environment" />
    </Machine>
    <Mobile>taken phone, test

when r1
    100m SUV
then
    FireFly is High
end


when r2
    Order of the Phonenix 
    
then
    Magic is High
end


</Mobile>
</Artificial>

My goal is to create a function that takes a line (string) and content (string) as input and returns the content of the closest tag that the provided line belongs to.

For example, if I provide the line FireFly is High, the expected output should be as follows since it is the closest tag that contains the provided line:

<Mobile>taken phone, test

when r1
    100m SUV
then
    FireFly is High
end


when r2
    Order of the Phonenix 

then
    Magic is High
end


</Mobile>

Below is the code snippet I have so far:

getLineContent(line: string, content: string) {
    const trimmedLine = line.trim()
    const isSelfClosingTag = /\/\s*>$/.test(trimmedLine)
    const isPlainTextLine = !/<|>/.test(trimmedLine)
    const regex = new RegExp(`(${trimmedLine}[^>]*>)([\\s\\S]*?)</(${trimmedLine.split(' ')[0].substr(1)}>)`)
    const isClosingTag = /^<\/\w+>$/.test(trimmedLine)
    const match = content.match(regex)

    if (!isClosingTag) {
      if (isSelfClosingTag) {
        return trimmedLine
      }

      if (match && match[2]) {
        return match[1] + match[2] + match[3]
      }
      if (isPlainTextLine) {
        const regex = new RegExp(`(<[^>]*>)([\\s\\S]*?${trimmedLine.split(' ')[0].substr(1)}[\\s\\S]*?</[a-zA-Z]+>)`)
        const match = content.match(regex)
        console.log('isPlainTextLine', match)
        if (match && match[1] && match[2]) {
          return match[2]
        }
      }
      return trimmedLine
    }
  }

The code works almost perfectly but there are still some issues, particularly in this part:

if (isPlainTextLine) {
        const regex = new RegExp(`(<[^>]*>)([\\s\\S]*?${trimmedLine.split(' ')[0].substr(1)}[\\s\\S]*?</[a-zA-Z]+>)`)
        const match = content.match(regex)
        console.log('isPlainTextLine', match)
        if (match && match[1] && match[2]) {
          return match[2]
        }
      }

For instance, providing FireFly is High results in:

<Machine>
        <MachineEnvironment uri="environment" />
    </Machine>
    <Mobile>taken phone, test

when r1
    100m SUV
then
    FireFly is High
end


when r2
    Order of the Phonenix 

then
    Magic is High
end


</Mobile>

I'm not very familiar with regex. Any assistance would be greatly appreciated.

Answer №1

For the task at hand, it is advised to steer clear of using Regex and opt for an XML parser instead. There are numerous options available in this regard. One such option is the fast-xml-parser, which effectively converts XML into a nested object structure. A demonstration can be seen below:

const { XMLParser } = require("fast-xml-parser");

function findText(obj, searchVal, key="") {
    if (typeof obj === "string" && obj.includes(searchVal)) {
        return { [key]: obj };
    }
    if (Object(obj) === obj) {
        for (const k in obj) {
            const result = findText(obj[k], searchVal, k);
            if (result) return result;
       }
    }
}

const xmlData = `<Artificial name="Artifical name">
    <Machine>
        <MachineEnvironment uri="environment" />
    <\/Machine>
    <Mobile>taken phone, test
    ...
    FireFly is High
    ...
    </Mobile>
<\/Artificial>`;

const parsedObj = new XMLParser().parse(xmlData);
const searchResult = findText(parsedObj, "FireFly");
console.log(searchResult); // { Mobile: "taken phone, ....... " }

Another approach would be to use the DOMParser within a browser environment:

function *iterateNodes(doc, whatToShow) { // Generator function for creating TreeWalker
    const walk = doc.createTreeWalker(doc.documentElement, whatToShow, null, false);
    for (let node; node = walk.nextNode(); null) yield node;
}

function findTagByContent(xmlData, contentToFind) {
    const document = new DOMParser().parseFromString(xmlData, "text/xml");
    for (const node of iterateNodes(document, NodeFilter.SHOW_TEXT)) {
        if (node.textContent.includes(contentToFind)) return node.parentNode.outerHTML;
    }
}

// Example usage

const xmlDoc = `<Artificial name="Artifical name">
    <Machine>
        <MachineEnvironment uri="environment" />
    </Machine>
    <Mobile>taken phone, test
    ...
    FireFly is High
    ...
    </Mobile>
</Artificial>`;

console.log(findTagByContent(xmlDoc, "FireFly"));

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The installation of the material ui package was unsuccessful

C:\Users\User\Desktop\client4>npm i @material-ui/icons npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree npm ERR! npm ERR! While resolving: [email protected] npm ERR! Found: [email protected] ...

Having trouble sending HTTP requests in Angular 6

I am currently facing an issue in my Angular application while trying to send an HTTP POST request to a Spring RESTful API. Despite my attempts, I have not been able to succeed and I do not see any error response in the browser console. Below is a snippet ...

Creating a Website for Compatibility with NoScript

During my journey of building a nameplate site from the ground up for myself, I have delved into the realms of learning and establishing my online presence. The highlight of my project is a sleek tabbed site that employs AJAX and anchor navigation to seaml ...

Encountering a TypeScript error while calling a Vue lifecycle hook method

Struggling to call a method in a Vue root component from a lifecycle method in typescript? See below for a simple example that showcases this issue: import Vue from "vue"; class Game { a: number; b: number; constructor() { this.a = 3; ...

Sequelize: Query results do not have defined instance methods and properties

The Sequelize version is 6.6.2 Mysql2 version: 2.2.5 I have constructed my Model in the following manner and defined methods as shown: interface IUserAttributes { user_id: number; logon_name: string; user_password: string; full_name: string; di ...

The player remains unchanged

Hi, I am currently working on my app to update a player's age. To start off, I have added three players: const playerOne = store.dispatch(addPlayer({ firstName: 'Theo', lastName: 'Tziomakas', position: 'Goakeeper ...

Using a single package manager for both backend and frontend development - is it possible? (Yarn/NPM)

Before, I relied on NPM for server-side tasks and Bower for frontend. NPM would install packages in the node_modules/ directory, while a .bowerrc file directed package installations to public/lib. Recently, I've made the switch to Yarn from NPM, and ...

Is it possible to leverage specific client-side Javascript APIs on the server-side?

Exploring APIs designed for web browsers that require their .js code to return audio streams. In a broader sense, these APIs provide byte streams (such as audio) for playback in the browser. Is it possible to use these APIs in server-side Javascript frame ...

Getting directions using the node-googlemaps module in node.js can be achieved by following these steps

For the past day, I've been attempting to make progress with this Node.js Google Maps directions example, but so far, no success. Every time I run it, I keep seeing ·· √ OK » 2 honored (0.848s). I've previously asked a similar question on U ...

What is the functionality behind a free hosting website?

Is anyone familiar with websites like Hostinghood, where users can create a subdomain and upload HTML, CSS, etc.? I'm curious about how they operate and how I can create a similar site. This is my first question here, so please respond instead of disl ...

Is there a way to submit a PUT method form in Laravel seamlessly without having to refresh the page?

Below is the HTML form code used in my Laravel application: <button onclick="submitForm()">submit form using jquery ajax</button> <form name="fbCommentCountform" action="{{ route('blogs.update', ['id'=>$id]) }}"> ...

How can I incorporate a personalized SVG path to serve as a cursor on a webpage?

Is there a way to enhance the functionality of binding the 'mousemove' event to a div and moving it around the page while hiding the real cursor? Specifically, can we change the shape of the circle to an SVG path and drag the SVG path around the ...

What is the best way to save the outcomes of several asynchronous $.get calls into an array?

I have a challenge where I need to retrieve data from an API for each item in an array, and then store that data in another array for further processing. However, I suspect the issue lies in the asynchronous nature of the requests, as the data may not be ...

The source files are expected to be contained within the 'rootDir' directory, which is not located at 'c:/Users/hasit/Desktop/typescript/src'

Can someone assist me with separating the Src folder and public folder in my project? When I try to do it in the tsconfig.json file, I encounter this error: "'rootDir' is expected to contain all source files." I have followed instructions from a ...

Removing buttons from a table row dynamically

Below is how I am adding the Button to Element: (this.sample as any).element.addEventListener("mouseover", function (e) { if ((e.target as HTMLElement).classList.contains("e-rowcell")) { let ele: Element = e.target as Element; let ro ...

What is the reason for TypeScript disabling unsecure/non-strict compiler rules by default?

Recently, I found myself having to enable a slew of compiler options in my application: "alwaysStrict": true, "extendedDiagnostics": true, "noFallthroughCasesInSwitch": true, "noImplicitAny", true, "noImplicitThis", true, "noImplicitReturns": true, "noUnu ...

Conceal the menu in Angular Material when the mouse leaves the button

When the mouse hovers over a button, a menu is displayed on the website's toolbar. The menu is set to close when the mouse leaves a surrounding span element. Now, there is an attempt to also close the menu when the mouse leaves the triggering button i ...

Ways to insert a div element into the HTML display utilizing JavaScript

There's a method I'd like to use to dynamically add a div to the view using JavaScript. I attempted hiding the div on page load and then showing it through JavaScript. However, what ends up happening is that the div content appears briefly on l ...

Create a custom Android home screen widget using JavaScript or another programming language

I have a project in mind to create an Android App and include a home-screen widget. While I know it can be done with Native Android, my preference is to use JavaScript for development. Would anyone happen to know of any other solutions that allow the use ...

Jest mock module request causing a timeout issue

I am encountering an issue with the code snippet below in my application request.ts import request from 'request' export const funcA = async ( apiToken: string, body: any): Promise<any> => { return new Promise((resolve, reject) =&g ...