Warm tip: This article is reproduced from serverfault.com, please click

Why does soap lib removes namespace from list entries/arrays

发布于 2020-12-02 16:51:55

My following Javascript function uses the Node.js Library "soap" to generate and send an XML SOAP request:

async function handle(req, res) {
    console.log('details...');

    soap.createClientAsync(API.bahn.search, {wsdl_headers: {Authorization: BahnCreds.basic.hash()}}).then(client => {
        client.setSecurity(new soap.BasicAuthSecurity(BahnCreds.basic.user, BahnCreds.basic.pwd));
        client.addHttpHeader('Authorization', BahnCreds.basic.hash());
        // console.debug(client.describe()); // Methodenliste

        const args = {
            RequestData: {
                attributes: {
                    ot: fns.format(new Date(), 'yyyyMMddhhmmss'),
                },
                'WL5G3N3:TariffIdentificationH': {
                    attributes: {
                        t: req.body.ticketid,
                        c: req.body.class,
                    }
                },
                'WL5G3N3:TravelerList': {
                    Traveler: {
                        attributes: {
                            age: 35
                        }
                    }
                },
                'WL5G3N3:ScheduleH': {
                    attributes: {
                        sid: req.body.sid,
                        dt: req.body.date,
                    },
                    'WL5G3N3:TrainList': {
                        'WL5G3N3:Train': req.body.trains.map(train => {
                            return {attributes: train};
                        })
                    }
                },
            },
            Header: header.get(),
        };
        console.log(JSON.stringify(args));

        const callback = (error, result) => {
            console.debug(client.lastRequest);
            if(!error) {
                return res.json({
                    result: result,
                    type: 'success',
                })
            }
            return res.json(Object.assign({},
                Errors.ERR__FEHLER_BEI_ABFRAGE,
                {details: error}));
        };
        return client
            .WSDReiseAuskunftInterface
            .WSDReiseAuskunftPort
            .Angebotsdetails(args, callback);
    });
}

The generated XML looks like this:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:WL5G3N1="http://www.bahn.de/webservices/dritte/angebotssuche/request"
    xmlns:WL5G3N2="http://www.bahn.de/webservices/dritte/angebotssuche/response"
    xmlns:WL5G3N3="http://www.bahn.de/webservices/dritte/angebotsdetails/request"
    xmlns:WL5G3N4="http://www.bahn.de/webservices/dritte/angebotsdetails/response"
    xmlns:WL5G3N5="http://www.bahn.de/webservices/dritte/ping/request"
    xmlns:WL5G3N6="http://www.bahn.de/webservices/dritte/ping/response"
    xmlns:WL5G3N7="http://www.bahn.de/webservices/dritte/monitoring/request"
    xmlns:WL5G3N8="http://www.bahn.de/webservices/dritte/monitoring/response"
    xmlns:WL5G3N9="http://www.bahn.de/webservices/dritte"
    xmlns:adreq="http://www.bahn.de/webservices/dritte/angebotsdetails/request"
    xmlns:adres="http://www.bahn.de/webservices/dritte/angebotsdetails/response"
    xmlns:asreq="http://www.bahn.de/webservices/dritte/angebotssuche/request"
    xmlns:asres="http://www.bahn.de/webservices/dritte/angebotssuche/response"
    xmlns:monreq="http://www.bahn.de/webservices/dritte/monitoring/request"
    xmlns:monres="http://www.bahn.de/webservices/dritte/monitoring/response"
    xmlns:pingreq="http://www.bahn.de/webservices/dritte/ping/request"
    xmlns:pingres="http://www.bahn.de/webservices/dritte/ping/response">
    <soap:Header></soap:Header>
    <soap:Body>
        <WL5G3N3:AngebotsdetailsRequest xmlns:WL5G3N3="http://www.bahn.de/webservices/dritte/angebotsdetails/request"
            xmlns="http://www.bahn.de/webservices/dritte/angebotsdetails/request">
            <WL5G3N3:RequestData ot="20201202052152">
                <WL5G3N3:TariffIdentificationH t="TCK#13#0#0#0#S2#6290#" c="2"></WL5G3N3:TariffIdentificationH>
                <WL5G3N3:TravelerList>
                    <db:Traveler age="35"
                        xmlns:db="http://www.bahn.de/webservices/dritte/datatypes/db"></db:Traveler>
                </WL5G3N3:TravelerList>
                <WL5G3N3:ScheduleH sid="0" dt="20201204">
                    <WL5G3N3:TrainList>
                        <ns1:Train arr="00d00:36:00" d="8000207" dep="00d00:14:00" dn="Köln Hbf" lt="Transport" s="8000085" sn="Düsseldorf Hbf" tid="0.0" tn="ICE  842"></ns1:Train>
                        <ns1:Train arr="00d01:25:00" d="8000044" dep="00d00:56:00" dn="Bonn Hbf" lt="Transport" s="8000207" sn="Köln Hbf" tid="0.1" tn="RB 25401"></ns1:Train>
                    </WL5G3N3:TrainList>
                </WL5G3N3:ScheduleH>
            </WL5G3N3:RequestData>
            <WL5G3N3:Header l="DE" t="" us="" pwd="" sig="" tnr=""></WL5G3N3:Header>
        </WL5G3N3:AngebotsdetailsRequest>
    </soap:Body>
</soap:Envelope>

This request results in an error, because WL5G3N3:Train has changed to ns1:Train. I think, it's related to the fact that WL5G3N3:Train is an array.

My question now is: why does this happen? Does anyone know, how I've to configure SOAP that arrays won't lose their namespace?

Questioner
Fabian
Viewed
0
Fabian 2020-12-04 04:47:50

The solution is to explicitly override the namespace after the client is created.

client.wsdl.definitions.xmlns.ns1 = http://your-namespace-url...;
client.wsdl.xmlnsInEnvelope = client.wsdl._xmlnsMap()

Then we can also get rid of the hardcoded namespaces. The function now looks like this:

async function handle(req, res) {
    console.log('details...');

    soap.createClientAsync(API.bahn.search, {wsdl_headers: {Authorization: BahnCreds.basic.hash()}}).then(client => {
        client.setSecurity(new soap.BasicAuthSecurity(BahnCreds.basic.user, BahnCreds.basic.pwd));
        client.addHttpHeader('Authorization', BahnCreds.basic.hash());

        // THIS WAS/IS IMPORTANT
        client.wsdl.definitions.xmlns.ns1 = API.bahn.ns.details;
        client.wsdl.xmlnsInEnvelope = client.wsdl._xmlnsMap()

        const args = {
            RequestData: {
                attributes: {
                    ot: fns.format(new Date(), 'yyyyMMddhhmmss'),
                },
                TariffIdentificationH: {
                    attributes: {
                        t: req.body.ticketid,
                        c: req.body.class,
                    }
                },
                TravelerList: {
                    Traveler: {
                        attributes: {
                            age: 35
                        }
                    }
                },
                ScheduleH: {
                    attributes: {
                        sid: req.body.sid,
                        dt: req.body.date,
                    },
                    TrainList: {
                        Train: req.body.trains
                    }
                },
            },
            Header: header.get(),
        };

        const callback = (error, result) => {
            if(!error) {
                return res.json({
                    result: result,
                    type: 'success',
                })
            }
            return res.json(Object.assign({},
                Errors.ERR__FEHLER_BEI_ABFRAGE,
                {details: error}));
        };
        return client
            .WSDReiseAuskunftInterface
            .WSDReiseAuskunftPort
            .Angebotsdetails(args, callback);
    });
}