Convert XML data into a string with nested parentheses

In an attempt to unravel an XML string using a regular expression, my goal is to construct a coherent string from it.

The XML string represents a complex boolean expression with nested elements.

Currently, I can extract the values involved in equalities, but I'm struggling to capture the AND/OR operators as well as the necessary parentheses for the final output.

Here is a snippet of the XML structure:

<applic id="TCTO_709_PRE_ALL">
<displayText><simplePara>All Aircraft without Extended Range Capability</simplePara></displayText>
<!--BEGIN OR-->
<evaluate andOr="or"> 
<!-- ( -->
  <assert applicPropertyIdent="partno" applicPropertyType="prodattr" applicPropertyValues="UHK97000-15" />
<!--BEGIN AND-->
 <evaluate andOr="and">     
  <!-- ( -->
<!--BEGIN OR-->
     <evaluate andOr="or">
     <!-- ( -->
        <assert applicPropertyIdent="partno" applicPropertyType="prodattr" applicPropertyValues="UHK97000-10" />
        <assert applicPropertyIdent="partno" applicPropertyType="prodattr" applicPropertyValues="UHK97000-12" />
     <!-- ) -->
     </evaluate>
<!--BEGIN OR-->
     <evaluate andOr="or">
      <!-- ( -->
        <assert applicPropertyIdent="TCTO_1Q-9A-709" applicPropertyType="condition" applicPropertyValues="PRE" />
        <assert applicPropertyIdent="TCTO_1Q-9A-709" applicPropertyType="condition" applicPropertyValues="NOI" />
      <!-- ) -->
     </evaluate>
     <!-- ) -->
  </evaluate>
  <!-- ) -->
 </evaluate>
</applic>

All <assert> elements are contained within either AND or OR <evaluate> elements.

This is the desired outcome based on the provided XML:

(partno="UHK97000-15" or ((partno="UHK97000-10" or partno="UHK97000-12") and (TCTO_1Q-9A-709="PRE" or TCTO_1Q-9A-709="NOI"))) 

Below is the script I am currently working with:

var sApplic = '<applic id="TCTO_709_PRE_ALL"><displayText><simplePara>All Aircraft without Extended Range Capability</simplePara></displayText><evaluate andOr="or"><assert applicPropertyIdent="partno" applicPropertyType="prodattr" applicPropertyValues="UHK97000-15"></assert><evaluate andOr="and"><evaluate andOr="or"><assert applicPropertyIdent="partno" applicPropertyType="prodattr" applicPropertyValues="UHK97000-10"></assert><assert applicPropertyIdent="partno" applicPropertyType="prodattr" applicPropertyValues="UHK97000-12"></assert></evaluate><evaluate andOr="or"><assert applicPropertyIdent="TCTO_1Q-9A-709" applicPropertyType="condition" applicPropertyValues="PRE"></assert><assert applicPropertyIdent="TCTO_1Q-9A-709" applicPropertyType="condition" applicPropertyValues="NOI"></assert></evaluate></evaluate></evaluate></applic>';
var sRegXEval = /<assert applicPropertyIdent="(.*?)" applicPropertyType=".*?" applicPropertyValues=(".*?")(\/>|<\/assert>)?/g;
var sMatch = sRegXEval.exec(sApplic);
while (sMatch != null) { 
        var sFirst = sMatch[1] + "=" + sMatch[2];
          document.write("<p>sMatch[" + i +"]" + sFirst);
    sMatch = sRegXEval.exec(sApplic);
    i++;
}
</script>

Despite running the above script, the results fall short of the anticipated output:

sMatch[0]partno="UHK97000-15"
sMatch[1]partno="UHK97000-10"
sMatch[2]partno="UHK97000-12"
sMatch[3]TCTO_1Q-9A-709="PRE"
sMatch[4]TCTO_1Q-9A-709="NOI"

How can I enhance the code to align with the desired result?

UPDATE: The original XML string has been updated to:

var sApplic = '<datamodule><file>CClasic.sgm</file><applic><displayText><simplePara>Cooking Classics</simplePara></displayText><assert applicPropertyIdent="author" applicPropertyType="prodattr" applicPropertyValues="Crocker"/></applic></datamodule>';

Due to this change, the previous script provided by @trincot is no longer applicable. How can I modify the script to accommodate this new string while also incorporating the display of the file name within the <file> element?

Answer №1

Avoid attempting to parse XML using regular expressions as they are not well-suited for this task.

Instead, utilize the DOM parser provided by the Web API in all major browsers, along with a recursive function that will handle the insertion of boolean operators and parentheses:

function processNode(node) {
    return Array.from(node.children, child =>
        child.tagName === 'assert'
            ? child.getAttribute('applicPropertyIdent') 
                + '="' + child.getAttribute('applicPropertyValues') + '"'
            : child.tagName === 'evaluate'
                ? '(' + processNode(child) + ')'
                : processNode(child)
    ).filter(Boolean).join(' ' + node.getAttribute('andOr') + ' ');
}

const sampleXML = `<datamodule>
<file>CClasic.sgm</file>
<applic id="TCTO_709_PRE_ALL"> 
    <displayText>
        <simplePara>All Aircraft without Extended Range Capability</simplePara>
    </displayText>
    <evaluate andOr="or">
        <assert applicPropertyIdent="partno" applicPropertyType="prodattr" applicPropertyValues="UHK97000-15"></assert>
        <evaluate andOr="and">
            <evaluate andOr="or">
                <assert applicPropertyIdent="partno" applicPropertyType="prodattr" applicPropertyValues="UHK97000-10"></assert>
                <assert applicPropertyIdent="partno" applicPropertyType="prodattr" applicPropertyValues="UHK97000-12"></assert>
            </evaluate>
            <evaluate andOr="or">
                <assert applicPropertyIdent="TCTO_1Q-9A-709" applicPropertyType="condition" applicPropertyValues="PRE"></assert>
                <assert applicPropertyIdent="TCTO_1Q-9A-709" applicPropertyType="condition" applicPropertyValues="NOI"></assert>
            </evaluate>
        </evaluate>
    </evaluate>
    </applic>
</datamodule>`;

const parsedXml = ( new window.DOMParser() ).parseFromString(sampleXML, "text/xml");
const finalResult = processNode(parsedXml.documentElement);
console.log(finalResult);

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

Running a function following several iterations of angular.forEach

let values1 = [1, 2, 3]; angular.forEach(values1, function(value){ $compile(value)($scope); }); let values2 = ['a', 'b', 'c']; angular.forEach(values2, function(value){ $compile(value)($scope ...

JavaScript refuses to connect with HTML

Just starting out in the world of programming, I decided to dive into a Programming Foundations class on Lynda.com. However, after following along for fifteen minutes, I encountered an issue - I couldn't seem to connect my JavaScript file to my HTML f ...

Issue with displaying Angular variable on webpage is not happening as expected

It's been a challenging journey trying to self-teach myself Angular.js. Unfortunately, I've hit a frustrating roadblock - the variables just won't display properly on the webpage! <!DOCTYPE html> <html ng-app> <head> & ...

Is there an Angular directive that can replicate a mouseenter event?

Is there a way to simulate a mouseenter event with a directive? I have been searching for a directive that can simulate a mouseenter event, but all I have found so far is one that binds a function to mouse over or karma tests for simulating mouse over. W ...

What is the best way to center text on an HTML canvas?

Is it possible to center an h1 tag in the middle of an HTML canvas using either JavaScript or HTML? I already have a CSS file for canvas styles. HTML <body> <canvas id="myCanvas"></canvas> <script src="canvas.js"></scri ...

Understanding Joi validation - setting a field as optional depending on the input received

I have been struggling to integrate the following joi validation. joiSchema = Joi.object().keys({ taskno: Joi.string().alphanum().required().uppercase().trim(), taskstatus: Joi.valid('G', 'C', 'I', 'S'), ...

What could be causing my Java "for" loop to suddenly terminate?

After successfully building the array in my initial loop, I encountered a problem when attempting to print out the results in the second "for" loop as it abruptly terminates. Despite thorough inspection, I cannot seem to find the error in my code. Here i ...

Conceal the div when the horizontal scroll position of the container is at 0

Struggling with a JavaScript issue in a fluid width page that involves scrolling a div using navigation buttons. I am new to JavaScript and trying to use scrollLeft = 0 to hide the leftmost nav button if there's nothing to scroll, and to show the div ...

No data being displayed or returned from API when using async await

My Ionic 6 + Angular 14 application is currently facing an issue with displaying data retrieved from an API... I have implemented a service to fetch the data from the API and then called this service in the component. The app compiles without any errors a ...

"Can you tell me a way to identify variances between two dates displayed in a

I am looking to calculate the differences between two dates. I will input the date values in the text box and want the duration to be displayed in another text box. <script language=javascript> function formshowhide(id) { if (id == ...

Integrate @azure/msal-node for user authentication to securely access resources in Azure Vault

Hey there, I've set up a test azure instance and am currently attempting to access a secret stored in a vault. The vault has been created, and my goal is to retrieve access using an electron application without storing any client secrets within the ...

Converting a one-dimensional array into a two-dimensional array in JavaScript explained

Below is the code snippet const arrayColumn = (arr, n) => arr.map(x => x[n]); const pcorr = (x, y) => { let sumX = 0, sumY = 0, sumXY = 0, sumX2 = 0, sumY2 = 0; const minLength = x.length = y.length = Math.min(x.length, y.le ...

Node.js reads and writes a JSON file, encountering issues with another application in the process

I'm currently facing an issue with my node.js server (express.js) and a json file used for reading and writing data through a simple API. Interestingly, when the node.js server is stopped, another application can add data to the json file without any ...

Malfunctioning JavaScript timepiece

I am currently experimenting with using Raphael to create a unique clock feature on my website. My goal is to animate the seconds hand to mimic the movement of a traditional clock. Below is the code snippet I have implemented: window.onload = function( ...

Using JavaScript to Calculate Distance from Wifi Signal Strength (RSSI)

Has anyone discovered a reliable method for converting an RSSI signal to an accurate distance? We have experimented with various formulas, but each one yields a different outcome. One formula in particular that we've been testing is as follows: pub ...

Connecting to a specific slide within a carousel using an array of thumbnails

Utilizing a gallery field from ACF in WordPress, I aim to showcase all images as thumbnails with a Masonry layout. When an image is clicked, it should open a carousel within a modal and navigate directly to the corresponding slide. The code below effectiv ...

Switching a set of checkboxes with a main checkbox

I've got this JS code that's doing its job and satisfying all my requirements when one of the checkboxes at the top is checked. However, I'm struggling to uncheck them by following the same process (unchecking the first box is not possible). ...

``Creating apertures in a rectangular shape using three.js: A step-by-step guide

I've been attempting to create two holes in a simple rectangle using three.js, but I'm facing an issue where the holes aren't showing up correctly with a 3D effect. Below is my current approach: const modelContainer = document.getElementByI ...

What is the best way to emphasize colors in search results?

Is it possible to assist in highlighting the searched words in yellow? Below is an example of code that filters words from the displayed data from a JSON feed URL. angular.module('sample', []). controller('sampleController', [' ...

Navigate through the page and once you reach a specific point, scroll the element

I'm feeling a bit stuck on how to achieve this particular effect. Imagine a web page where, as a user scrolls down, a specific element responds to the mouse scroll input by appearing to move along with the scrolling motion. Once that element reaches ...