1

So as you can see, we have this XML

<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <soapenv:Body>
        <GetECConfigResponse xmlns="urn:ecs.wsapi.broadon.com">
            <Version>2.0</Version>
            <DeviceId>4498122730</DeviceId>
            <MessageId>ECDK-4498122730-39653600512638909</MessageId>
            <TimeStamp>1599408189821</TimeStamp>
            <ErrorCode>0</ErrorCode>
            <ServiceStandbyMode>false</ServiceStandbyMode>
            <ContentPrefixURL>http://example.com</ContentPrefixURL>
            <UncachedContentPrefixURL>http://example.com</UncachedContentPrefixURL>
            <SystemContentPrefixURL>http://example.com</SystemContentPrefixURL>
            <SystemUncachedContentPrefixURL>http://example.com</SystemUncachedContentPrefixURL>
            <EcsURL>http://example.com</EcsURL>
            <IasURL>http://example.com</IasURL>
            <CasURL>http://example.com</CasURL>
            <NusURL>http://example.com</NusURL>
        </GetECConfigResponse>
    </soapenv:Body>
</soapenv:Envelope>

I do this so I can edit stuff inside the xml depending on the user's POST body but I have to edit the stuff I want, and turn it into a XML back again and send it as a response, since it's not possible with Node.JS to edit the XML directly without converting to JS or JSON

const xmlParser = require("xml2json");
var json2xml = require("json2xml");

// Current time in epoch
function currentEpoch() {
    const now = Date.now()
        return now
}
// Read the XML file
fs.readFile("./ecs/ecommercesoap/getecconfigresponse.xml", function (err, data) {
    // Convert the XML to JSON
    const xmlObj = xmlParser.toJson(data, {
        object: true
    })
        // Get the user's body details
        var deviceId = req.body["DeviceId"]
        // Change XML index depending on the user
        xmlObj["soapenv:Envelope"]["soapenv:Body"]["GetECConfigResponse"]["DeviceId"] = deviceId
        xmlObj["soapenv:Envelope"]["soapenv:Body"]["GetECConfigResponse"]["TimeStamp"] = currentEpoch().toString()

This is where it converts xmlObj back to xml again

// Convert the JSON to XML and finalize it
    const finalXml = xmlParser.toXml(xmlObj)
    
// Set the response's type as application/xml
    res.type('application/xml');
    
// Sending the completely edited XML back to the user
    res.send(finalXml)

And as you can see, the output changes when the converting happens. The XML below is after it's edited and parsed back into XML from JSON. If you noticed, <?xml version="1.0" encoding="utf-8"?> is also deleted, which shouldn't be.

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <soapenv:Body>
        <GetECConfigResponse xmlns="urn:ecs.wsapi.broadon.com" Version="2.0" DeviceId="4498122730" MessageId="ECDK-4498122730-39653600512638909" TimeStamp="1599505063565" ErrorCode="0" ServiceStandbyMode="false" ContentPrefixURL="http://example.com" UncachedContentPrefixURL="http://example.com" SystemContentPrefixURL="http://example.com" SystemUncachedContentPrefixURL="http://example.com" EcsURL="http://example.com" IasURL="http://example.com" CasURL="http://example.com" NusURL="http://example.com"/>
    </soapenv:Body>
</soapenv:Envelope>

So I wonder what can I do to fix this, the tags start and end with <> in the original while edited one doesn't even have it. Long story short, bunch of stuff got changed. I also tried xml2js instead of xml2json but the output is still the same. I just want my output exactly same as the original file, but with my stuff changed.

3
  • Why don't you use something like soap package? Commented Sep 7, 2020 at 20:30
  • I am okay with what I use right now and that's not the case either. Commented Sep 7, 2020 at 20:34
  • I'm having trouble seeing any good reason for converting the XML to JSON and back again. Why don't you simply do the transformation in XSLT? Commented Sep 7, 2020 at 22:10

1 Answer 1

3

In our project we have to deal with manually modifiying soap/xml in NodeJS as well - we've recently switched to fast-xml-parser and are really happy with it. I took your sample input and using the following code:

const xmlToJsonParser = require('fast-xml-parser');
const options = {
    ignoreAttributes: false,
    ignoreNameSpace: false,
    parseNodeValue: true,
    parseAttributeValue: true,
    trimValues: true,
};
// xmlData refers to the xml-string 
const tObj = xmlToJsonParser.getTraversalObj(xmlData, options);
const jsonObj = xmlToJsonParser.convertToJson(tObj, options);
// modify json
jsonObj["soapenv:Envelope"]["soapenv:Body"]["GetECConfigResponse"].DeviceId = 123456;

const JsonToXmlParser = require("fast-xml-parser").j2xParser;
const parser = new JsonToXmlParser({format: true, ignoreAttributes: false});
const xml = parser.parse(jsonObj);
console.log(xml);

it produces:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Body>
    <GetECConfigResponse xmlns="urn:ecs.wsapi.broadon.com">
      <Version>2</Version>
      <DeviceId>123456</DeviceId>
      <MessageId>ECDK-4498122730-39653600512638909</MessageId>
      <TimeStamp>1599408189821</TimeStamp>
      <ErrorCode>0</ErrorCode>
      <ServiceStandbyMode>false</ServiceStandbyMode>
      <ContentPrefixURL>http://example.com</ContentPrefixURL>
      <UncachedContentPrefixURL>http://example.com</UncachedContentPrefixURL>
      <SystemContentPrefixURL>http://example.com</SystemContentPrefixURL>
      <SystemUncachedContentPrefixURL>http://example.com</SystemUncachedContentPrefixURL>
      <EcsURL>http://example.com</EcsURL>
      <IasURL>http://example.com</IasURL>
      <CasURL>http://example.com</CasURL>
      <NusURL>http://example.com</NusURL>
    </GetECConfigResponse>
  </soapenv:Body>
</soapenv:Envelope>

All that's left is to prepend the xml-header, as they've decided to exclude this feature from the parser (https://github.com/NaturalIntelligence/fast-xml-parser/issues/184).

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you for the quick answer! I'd like to know how can I read the xml file because when I tried it with my fs code in the question, I got a weird error xmlData = xmlData.replace(/(\r\n)|\n/, " "); TypeError: xmlData.replace is not a function
Have you checked err in the callback? You need to make sure it's not defined before continuing.
Can you add a console.log(xmlData) after reading the file, please?
Thank you for solving the issue! You're the best.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.