Optimize XML parsing
Using XPath expressions appears to be expensive so that has been replaced with direct child node access. This seems to have improved performance by 5%. A side effect of this change is that XML_IGNORE_NAMESPACE option is no longer needed as namespaces are ignored by default.
This commit is contained in:
1 parent
037aa9786d
commit
ec215ffb82
2 files changed
+239
-121
No files matched your search
@@ -79,7 +79,6 @@ const options = {
|
|||||||
XML_FORMAT: { type: "bool", default: false },
|
XML_FORMAT: { type: "bool", default: false },
|
||||||
XML_NO_DECL: { type: "bool", default: false },
|
XML_NO_DECL: { type: "bool", default: false },
|
||||||
XML_NO_EMPTY: { type: "bool", default: false },
|
XML_NO_EMPTY: { type: "bool", default: false },
|
||||||
XML_IGNORE_NAMESPACE: { type: "bool", default: false },
|
|
||||||
|
|
||||||
// Should probably never be changed
|
// Should probably never be changed
|
||||||
DEVICE_ONLINE_THRESHOLD: { type: "int", default: 4000 }
|
DEVICE_ONLINE_THRESHOLD: { type: "int", default: 4000 }
|
||||||
@@ -106,9 +105,6 @@ function setConfig(name, value, commandLineArgument) {
|
|||||||
)
|
)
|
||||||
setConfig("GPV_BATCH_SIZE", value);
|
setConfig("GPV_BATCH_SIZE", value);
|
||||||
|
|
||||||
if (name === "IGNORE_XML_NAMESPACES" || name === "ignore-xml-namespaces")
|
|
||||||
setConfig("XML_IGNORE_NAMESPACE", value);
|
|
||||||
|
|
||||||
if (name === "XML_PARSE_IGNORE_ENC" || name === "xml-parse-ignore-enc")
|
if (name === "XML_PARSE_IGNORE_ENC" || name === "xml-parse-ignore-enc")
|
||||||
setConfig("XML_IGNORE_ENC", value);
|
setConfig("XML_IGNORE_ENC", value);
|
||||||
|
|
||||||
|
|||||||
+239
-117
@@ -74,18 +74,6 @@ const LIBXMLJS_SAVE_OPTIONS = {
|
|||||||
selfCloseEmpty: !config.get("XML_NO_EMPTY")
|
selfCloseEmpty: !config.get("XML_NO_EMPTY")
|
||||||
};
|
};
|
||||||
|
|
||||||
const XML_IGNORE_NAMESPACE = config.get("XML_IGNORE_NAMESPACE");
|
|
||||||
|
|
||||||
if (XML_IGNORE_NAMESPACE) {
|
|
||||||
libxmljs.Element.prototype.__find = libxmljs.Element.prototype.find;
|
|
||||||
libxmljs.Element.prototype.find = function(xpath, namespaces) {
|
|
||||||
const p = xpath
|
|
||||||
.replace(/([^/:]+:)?([^/]+)(\/|$)/g, "$2$3")
|
|
||||||
.replace(/([a-zA-Z0-9_-]+)([^/]*)(\/|$)/g, '*[local-name()="$1"]$2$3');
|
|
||||||
return libxmljs.Element.prototype.__find.call(this, p, namespaces);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let warnings;
|
let warnings;
|
||||||
|
|
||||||
function parseBool(v) {
|
function parseBool(v) {
|
||||||
@@ -97,13 +85,35 @@ function parseBool(v) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function event(xml) {
|
function event(xml) {
|
||||||
return xml.find("EventStruct/EventCode").map(e => e.text().trim());
|
return xml
|
||||||
|
.childNodes()
|
||||||
|
.filter(n => n.name() === "EventStruct")
|
||||||
|
.map(c =>
|
||||||
|
c
|
||||||
|
.childNodes()
|
||||||
|
.find(n => n.name() === "EventCode")
|
||||||
|
.text()
|
||||||
|
.trim()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function parameterInfoList(xml) {
|
function parameterInfoList(xml) {
|
||||||
return xml.find("ParameterInfoStruct").map(e => {
|
return xml
|
||||||
const param = e.get("Name").text();
|
.childNodes()
|
||||||
const value = e.get("Writable").text();
|
.filter(e => e.name() === "ParameterInfoStruct")
|
||||||
|
.map(e => {
|
||||||
|
let param, value;
|
||||||
|
for (const c of e.childNodes()) {
|
||||||
|
switch (c.name()) {
|
||||||
|
case "Name":
|
||||||
|
param = c.text();
|
||||||
|
break;
|
||||||
|
case "Writable":
|
||||||
|
value = c.text();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let parsed = parseBool(value);
|
let parsed = parseBool(value);
|
||||||
|
|
||||||
if (parsed === null) {
|
if (parsed === null) {
|
||||||
@@ -119,10 +129,23 @@ function parameterInfoList(xml) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function parameterValueList(xml) {
|
function parameterValueList(xml) {
|
||||||
return xml.find("ParameterValueStruct").map(e => {
|
return xml
|
||||||
const valueElement = e.get("Value");
|
.childNodes()
|
||||||
|
.filter(e => e.name() === "ParameterValueStruct")
|
||||||
|
.map(e => {
|
||||||
|
let valueElement, param;
|
||||||
|
for (const c of e.childNodes()) {
|
||||||
|
switch (c.name()) {
|
||||||
|
case "Name":
|
||||||
|
param = c.text();
|
||||||
|
break;
|
||||||
|
case "Value":
|
||||||
|
valueElement = c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const valueType = valueElement.attr("type").value();
|
const valueType = valueElement.attr("type").value();
|
||||||
const param = e.get("Name").text();
|
|
||||||
const value = valueElement.text();
|
const value = valueElement.text();
|
||||||
let parsed = value;
|
let parsed = value;
|
||||||
if (valueType === "xsd:boolean") {
|
if (valueType === "xsd:boolean") {
|
||||||
@@ -167,7 +190,9 @@ function GetParameterNames(xml, methodRequest) {
|
|||||||
function GetParameterNamesResponse(xml) {
|
function GetParameterNamesResponse(xml) {
|
||||||
return {
|
return {
|
||||||
name: "GetParameterNamesResponse",
|
name: "GetParameterNamesResponse",
|
||||||
parameterList: parameterInfoList(xml.get("ParameterList"))
|
parameterList: parameterInfoList(
|
||||||
|
xml.childNodes().find(n => n.name() === "ParameterList")
|
||||||
|
)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,7 +208,9 @@ function GetParameterValues(xml, methodRequest) {
|
|||||||
function GetParameterValuesResponse(xml) {
|
function GetParameterValuesResponse(xml) {
|
||||||
return {
|
return {
|
||||||
name: "GetParameterValuesResponse",
|
name: "GetParameterValuesResponse",
|
||||||
parameterList: parameterValueList(xml.get("ParameterList"))
|
parameterList: parameterValueList(
|
||||||
|
xml.childNodes().find(n => n.name() === "ParameterList")
|
||||||
|
)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,7 +247,12 @@ function SetParameterValues(xml, methodRequest) {
|
|||||||
function SetParameterValuesResponse(xml) {
|
function SetParameterValuesResponse(xml) {
|
||||||
return {
|
return {
|
||||||
name: "SetParameterValuesResponse",
|
name: "SetParameterValuesResponse",
|
||||||
status: parseInt(xml.get("Status").text())
|
status: parseInt(
|
||||||
|
xml
|
||||||
|
.childNodes()
|
||||||
|
.find(n => n.name() === "Status")
|
||||||
|
.text()
|
||||||
|
)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,10 +263,22 @@ function AddObject(xml, methodRequest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function AddObjectResponse(xml) {
|
function AddObjectResponse(xml) {
|
||||||
|
let instanceNumber, status;
|
||||||
|
for (const c of xml.childNodes()) {
|
||||||
|
switch (c.name()) {
|
||||||
|
case "InstanceNumber":
|
||||||
|
instanceNumber = parseInt(c.text());
|
||||||
|
break;
|
||||||
|
case "Status":
|
||||||
|
status = parseInt(c.text());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: "AddObjectResponse",
|
name: "AddObjectResponse",
|
||||||
instanceNumber: parseInt(xml.get("InstanceNumber").text()),
|
instanceNumber: instanceNumber,
|
||||||
status: parseInt(xml.get("Status").text())
|
status: status
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,7 +291,12 @@ function DeleteObject(xml, methodRequest) {
|
|||||||
function DeleteObjectResponse(xml) {
|
function DeleteObjectResponse(xml) {
|
||||||
return {
|
return {
|
||||||
name: "DeleteObjectResponse",
|
name: "DeleteObjectResponse",
|
||||||
status: parseInt(xml.get("Status").text())
|
status: parseInt(
|
||||||
|
xml
|
||||||
|
.childNodes()
|
||||||
|
.find(n => n.name() === "Status")
|
||||||
|
.text()
|
||||||
|
)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,31 +336,64 @@ function Download(xml, methodRequest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function DownloadResponse(xml) {
|
function DownloadResponse(xml) {
|
||||||
const res = {
|
let status, startTime, completeTime;
|
||||||
name: "DownloadResponse",
|
for (const c of xml.childNodes()) {
|
||||||
status: parseInt(xml.get("Status").text())
|
switch (c.name()) {
|
||||||
};
|
case "Status":
|
||||||
|
status = parseInt(c.text());
|
||||||
if (res.status === 0) {
|
break;
|
||||||
res.startTime = Date.parse(xml.get("StartTime").text());
|
case "StartTime":
|
||||||
res.completeTime = Date.parse(xml.get("CompleteTime").text());
|
startTime = Date.parse(c.text());
|
||||||
|
break;
|
||||||
|
case "CompleteTime":
|
||||||
|
completeTime = Date.parse(c.text());
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return {
|
||||||
|
name: "DownloadResponse",
|
||||||
|
status: status,
|
||||||
|
startTime: startTime,
|
||||||
|
completeTime: completeTime
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function Inform(xml) {
|
function Inform(xml) {
|
||||||
|
let retryCount, evnt, parameterList;
|
||||||
|
const deviceId = {
|
||||||
|
Manufacturer: null,
|
||||||
|
OUI: null,
|
||||||
|
ProductClass: null,
|
||||||
|
SerialNumber: null
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const c of xml.childNodes()) {
|
||||||
|
switch (c.name()) {
|
||||||
|
case "ParameterList":
|
||||||
|
parameterList = parameterValueList(c);
|
||||||
|
break;
|
||||||
|
case "DeviceId":
|
||||||
|
for (const cc of c.childNodes()) {
|
||||||
|
const n = cc.name();
|
||||||
|
if (n in deviceId) deviceId[n] = cc.text();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "Event":
|
||||||
|
evnt = event(c);
|
||||||
|
break;
|
||||||
|
case "RetryCount":
|
||||||
|
retryCount = parseInt(c.text());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: "Inform",
|
name: "Inform",
|
||||||
parameterList: parameterValueList(xml.get("ParameterList")),
|
parameterList: parameterList,
|
||||||
deviceId: {
|
deviceId: deviceId,
|
||||||
Manufacturer: xml.get("DeviceId/Manufacturer").text(),
|
event: evnt,
|
||||||
OUI: xml.get("DeviceId/OUI").text(),
|
retryCount: retryCount
|
||||||
ProductClass: xml.get("DeviceId/ProductClass").text(),
|
|
||||||
SerialNumber: xml.get("DeviceId/SerialNumber").text()
|
|
||||||
},
|
|
||||||
event: event(xml.get("Event")),
|
|
||||||
retryCount: parseInt(xml.get("RetryCount").text())
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,12 +418,30 @@ function GetRPCMethodsResponse(xml, methodResponse) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function TransferComplete(xml) {
|
function TransferComplete(xml) {
|
||||||
|
let commandKey, _faultStruct, startTime, completeTime;
|
||||||
|
for (const c of xml.childNodes()) {
|
||||||
|
switch (c.name()) {
|
||||||
|
case "CommandKey":
|
||||||
|
commandKey = c.text();
|
||||||
|
break;
|
||||||
|
case "FaultStruct":
|
||||||
|
_faultStruct = faultStruct(c);
|
||||||
|
break;
|
||||||
|
case "StartTime":
|
||||||
|
startTime = Date.parse(c.text());
|
||||||
|
break;
|
||||||
|
case "CompleteTime":
|
||||||
|
completeTime = Date.parse(c.text());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: "TransferComplete",
|
name: "TransferComplete",
|
||||||
commandKey: xml.get("CommandKey").text(),
|
commandKey: commandKey,
|
||||||
faultStruct: faultStruct(xml.get("FaultStruct")),
|
faultStruct: _faultStruct,
|
||||||
startTime: Date.parse(xml.get("StartTime").text()),
|
startTime: startTime,
|
||||||
completeTime: Date.parse(xml.get("CompleteTime").text())
|
completeTime: completeTime
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -352,7 +452,10 @@ function TransferCompleteResponse(xml) {
|
|||||||
function RequestDownload(xml) {
|
function RequestDownload(xml) {
|
||||||
return {
|
return {
|
||||||
name: "RequestDownload",
|
name: "RequestDownload",
|
||||||
fileType: xml.get("FileType").text()
|
fileType: xml
|
||||||
|
.childNodes()
|
||||||
|
.find(n => n.name() === "FileType")
|
||||||
|
.text()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,57 +464,104 @@ function RequestDownloadResponse(xml) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function faultStruct(xml) {
|
function faultStruct(xml) {
|
||||||
const f = {
|
let faultCode, faultString, setParameterValuesFault, pn, fc, fs;
|
||||||
faultCode: xml.get("FaultCode").text(),
|
for (const c of xml.childNodes()) {
|
||||||
faultString: xml.get("FaultString").text()
|
switch (c.name()) {
|
||||||
};
|
case "FaultCode":
|
||||||
|
faultCode = c.text();
|
||||||
for (const e of xml.find("SetParameterValuesFault")) {
|
break;
|
||||||
if (!f.setParameterValuesFault) f.setParameterValuesFault = [];
|
case "FaultString":
|
||||||
|
faultString = c.text();
|
||||||
f.setParameterValuesFault.push({
|
break;
|
||||||
parameterName: e.get("ParameterName").text(),
|
case "SetParameterValuesFault":
|
||||||
faultCode: e.get("FaultCode").text(),
|
setParameterValuesFault = setParameterValuesFault || [];
|
||||||
faultString: e.get("FaultString").text()
|
for (const cc of c.childNodes()) {
|
||||||
|
switch (cc.name()) {
|
||||||
|
case "ParameterName":
|
||||||
|
pn = cc.text();
|
||||||
|
break;
|
||||||
|
case "FaultCode":
|
||||||
|
fc = cc.text();
|
||||||
|
break;
|
||||||
|
case "FaultString":
|
||||||
|
fs = cc.text();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setParameterValuesFault.push({
|
||||||
|
parameterName: pn,
|
||||||
|
faultCode: fc,
|
||||||
|
faultString: fs
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return f;
|
return { faultCode, faultString, setParameterValuesFault };
|
||||||
}
|
}
|
||||||
|
|
||||||
function fault(xml, cwmpVersion) {
|
function fault(xml) {
|
||||||
return {
|
let faultCode, faultString, detail;
|
||||||
faultCode: xml.get("faultcode").text(),
|
for (const c of xml.childNodes) {
|
||||||
faultString: xml.get("faultstring").text(),
|
switch (c.name()) {
|
||||||
detail: faultStruct(xml.get("detail/cwmp:Fault", NAMESPACES[cwmpVersion]))
|
case "faultcode":
|
||||||
};
|
faultCode = c.text();
|
||||||
|
break;
|
||||||
|
case "faultstring":
|
||||||
|
faultString = c.text();
|
||||||
|
break;
|
||||||
|
case "detail":
|
||||||
|
detail = faultStruct(c.childNodes().find(n => n.name() === "Fault"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { faultCode, faultString, detail };
|
||||||
}
|
}
|
||||||
|
|
||||||
function request(data, cwmpVersion, warn) {
|
function request(data, cwmpVersion, warn) {
|
||||||
warnings = warn;
|
warnings = warn;
|
||||||
|
|
||||||
const rpc = {
|
const rpc = {
|
||||||
cwmpVersion: cwmpVersion
|
id: null,
|
||||||
|
cwmpVersion: cwmpVersion,
|
||||||
|
sessionTimeout: null,
|
||||||
|
cpeRequest: null,
|
||||||
|
cpeFault: null
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!data.length) return rpc;
|
if (!data.length) return rpc;
|
||||||
|
|
||||||
const xml = libxmljs.parseXml(data, LIBXMLJS_PARSE_OPTIONS);
|
const xml = libxmljs.parseXml(data, LIBXMLJS_PARSE_OPTIONS);
|
||||||
|
|
||||||
let methodElement;
|
let headerElement, bodyElement;
|
||||||
|
|
||||||
if (rpc.cwmpVersion) {
|
for (const c of xml.childNodes()) {
|
||||||
methodElement = xml.get(
|
switch (c.name()) {
|
||||||
"/soap-env:Envelope/soap-env:Body/cwmp:*",
|
case "Header":
|
||||||
NAMESPACES[rpc.cwmpVersion]
|
headerElement = c;
|
||||||
);
|
break;
|
||||||
} else {
|
case "Body":
|
||||||
// cwmpVersion not passed, thus it's an inform request
|
bodyElement = c;
|
||||||
methodElement = xml.get(
|
break;
|
||||||
"/soap-env:Envelope/soap-env:Body/*",
|
}
|
||||||
NAMESPACES["1.0"]
|
}
|
||||||
);
|
|
||||||
let timeoutElement;
|
for (const c of headerElement.childNodes()) {
|
||||||
|
switch (c.name()) {
|
||||||
|
case "ID":
|
||||||
|
rpc.id = c.text();
|
||||||
|
break;
|
||||||
|
case "sessionTimeout":
|
||||||
|
rpc.sessionTimeout = parseInt(c.text());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const methodElement of bodyElement.childNodes()) {
|
||||||
|
const methodName = methodElement.name();
|
||||||
|
if (methodName === "text") continue;
|
||||||
|
|
||||||
|
if (!rpc.cwmpVersion && methodName !== "Fault") {
|
||||||
switch (methodElement.namespace().href()) {
|
switch (methodElement.namespace().href()) {
|
||||||
case "urn:dslforum-org:cwmp-1-0":
|
case "urn:dslforum-org:cwmp-1-0":
|
||||||
rpc.cwmpVersion = "1.0";
|
rpc.cwmpVersion = "1.0";
|
||||||
@@ -420,16 +570,9 @@ function request(data, cwmpVersion, warn) {
|
|||||||
rpc.cwmpVersion = "1.1";
|
rpc.cwmpVersion = "1.1";
|
||||||
break;
|
break;
|
||||||
case "urn:dslforum-org:cwmp-1-2":
|
case "urn:dslforum-org:cwmp-1-2":
|
||||||
timeoutElement = xml.get(
|
if (rpc.sessionTimeout) rpc.cwmpVersion = "1.3";
|
||||||
"/soap-env:Envelope/soap-env:Header/cwmp:sessionTimeout",
|
else rpc.cwmpVersion = "1.2";
|
||||||
NAMESPACES["1.2"]
|
|
||||||
);
|
|
||||||
if (timeoutElement) {
|
|
||||||
rpc.sessionTimeout = parseInt(timeoutElement.text());
|
|
||||||
rpc.cwmpVersion = "1.3";
|
|
||||||
} else {
|
|
||||||
rpc.cwmpVersion = "1.2";
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case "urn:dslforum-org:cwmp-1-3":
|
case "urn:dslforum-org:cwmp-1-3":
|
||||||
rpc.cwmpVersion = "1.4";
|
rpc.cwmpVersion = "1.4";
|
||||||
@@ -437,27 +580,9 @@ function request(data, cwmpVersion, warn) {
|
|||||||
default:
|
default:
|
||||||
throw new Error("Unrecognized CWMP version");
|
throw new Error("Unrecognized CWMP version");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rpc.sessionTimeout) {
|
|
||||||
timeoutElement = xml.get(
|
|
||||||
"/soap-env:Envelope/soap-env:Header/cwmp:sessionTimeout",
|
|
||||||
NAMESPACES[rpc.cwmpVersion]
|
|
||||||
);
|
|
||||||
if (timeoutElement) rpc.sessionTimeout = parseInt(timeoutElement.text());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const idElement = xml.get(
|
switch (methodName) {
|
||||||
"/soap-env:Envelope/soap-env:Header/cwmp:ID",
|
|
||||||
NAMESPACES[rpc.cwmpVersion]
|
|
||||||
);
|
|
||||||
if (idElement) rpc.id = idElement.text();
|
|
||||||
|
|
||||||
if (
|
|
||||||
methodElement &&
|
|
||||||
!(XML_IGNORE_NAMESPACE && methodElement.name() === "Fault")
|
|
||||||
) {
|
|
||||||
switch (methodElement.name()) {
|
|
||||||
case "Inform":
|
case "Inform":
|
||||||
rpc.cpeRequest = Inform(methodElement);
|
rpc.cpeRequest = Inform(methodElement);
|
||||||
break;
|
break;
|
||||||
@@ -494,15 +619,12 @@ function request(data, cwmpVersion, warn) {
|
|||||||
case "DownloadResponse":
|
case "DownloadResponse":
|
||||||
rpc.cpeResponse = DownloadResponse(methodElement);
|
rpc.cpeResponse = DownloadResponse(methodElement);
|
||||||
break;
|
break;
|
||||||
|
case "Fault":
|
||||||
|
rpc.cpeFault = fault(methodElement, rpc.cwmpVersion);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`8000 Method not supported ${methodElement.name()}`);
|
throw new Error(`8000 Method not supported ${methodName}`);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
const faultElement = xml.get(
|
|
||||||
"/soap-env:Envelope/soap-env:Body/soap-env:Fault",
|
|
||||||
NAMESPACES[rpc.cwmpVersion]
|
|
||||||
);
|
|
||||||
rpc.cpeFault = fault(faultElement, rpc.cwmpVersion);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rpc;
|
return rpc;
|
||||||
|
|||||||
Reference in new issue
Block a user