node.jsxmlxml-builder

NodeJS checking if XML element exists and add or delete


I'm working with XML in NodeJS. I've been using the xmlbuilder to create my XML. The problem is that now I need to check if a element already exists and delete or update it. For example, I have the following XML

<?xml version="1.0"?>
<listings>
    <listing>
        <id>1</id>
        <name>TEST</name>
        <description>TEST</description>
    </listing>
    <listing>
        <id>2</id>
        <name>TEST</name>
        <description>TEST</description>
    </listing>
</listings>

Then, I call my updateXML controller to add data to it.

const builder = require('xmlbuilder');
const fs = require('fs');
const path = require("path");

exports.updateXML = async (req, res, next) => {
    const data = req.body.data;
    /* 
        For example data is
        {
            id: 2,
            name: "Test2",
            description: "Desc2"
        }
    */

    const xmlFile = fs.readFileSync(path.resolve(__dirname, "./oodle.xml"), 'utf8');
    
    if(/*How do I check if the xmlFile has a <id> === data.id?*/) {
        // If id matches. How can I delete the whole <listing> node for that id?
    }

    const newListing = builder.create('listing');
    newListing.ele("id", data.id);
    newListing.ele("name", data.name);
    newListing.ele("description", data.description);

    // How can I add the newListing node to the xmlFile?
}

Thanks


Solution

  • I don't believe it's really necessary to remove the node with the duplicate <id>, create a new <listing> node and then insert it into the xml. At least as far as the sample xml in your question is concerned, you can just modify the text child nodes of the relevant <listing> node.

    Something along the lines of:

    const { select } = require('xpath');
    
    let query = `//listing[./id[./text()="${data.id}"]]`;
    
    const nodes = select(query, doc.node);
     nodes.forEach(function (node) {
        nam = select('.//name/text()',node)
        desc = select('.//description/text()',node)
        nam[0].data = data.name;
        desc[0].data = data.description;
      });
     const serializedXML = doc.end({ format: 'xml', prettyPrint: true });
    
     console.log(serializedXML)
    

    Output:

    <?xml version="1.0"?>
    <listings>
      <listing>
        <id>1</id>
        <name>TEST</name>
        <description>TEST</description>
      </listing>
      <listing>
        <id>2</id>
        <name>Test2</name>
        <description>Desc2</description>
      </listing>
    </listings>