The purpose of this post is to learn the basics of working with XML and SOAP in AL. Besides,
we'll look at my suggestion of the generic API method SendRequest(), which fits most APIs without authorization.
The authorization itself is not difficult to add to the general logic, but in the post
, they are not considered due to their large number and often unique logic.
codeunit 81602 "SDA Temperature Conversion API"
{
procedure Convert(ConvertType: Enum "SDA Temperature Convert Type";
SoapVersion: Enum "SDA SOAP Version"; Temperature: Integer) NewTemperature: Text
var
DictionaryDefaultHeaders: Codeunit "Dictionary Wrapper";
BaseXMLDoc: XmlDocument;
XMLElem: XmlElement;
BodyNode: XmlNode;
ResultXPath: Text;
ContentToSend: Text;
ContentType: Text;
Result: Text;
begin
//Generate base XML request based on SOAP version
//w3schools temperature converter support SOAP 1.1 and SOAP 1.2
//depending on the SOAP version, we need to choose the correct namespace
//SOAPAction is required for SOAP 1.1
case SoapVersion of
SoapVersion::soap:
begin
BaseXMLDoc := CreateBaseXMLDoc(Format(SoapVersion),
SOAP11NamespaceURILbl);
ContentType := SOAP11XMLContentTypeLbl;
DictionaryDefaultHeaders.Set('SOAPAction', '');
end;
SoapVersion::soap12:
begin
BaseXMLDoc := CreateBaseXMLDoc(Format(SoapVersion),
SOAP12NamespaceUriLbl);
ContentType := SOAP12XMLContentTypeLbl;
end;
end;
//Generate body of request XML document in XMLElem variable
//AddChildElementWithTxtValue() used for append child node to parent
(first param)
//Fill ResultXPath variable based on Convert Type
//Set related SOAPAction for SOAP 1.1
case ConvertType of
ConvertType::"To Celsius":
begin
XMLElem := XmlElement.Create('FahrenheitToCelsius',
W3BaseNamespaceUriLbl);
AddChildElementWithTxtValue(XMLElem, 'Fahrenheit',
W3BaseNamespaceUriLbl, Format(Temperature));
ResultXPath := BodyXPathLbl + LocalXPathSeparatorLbl
+ StrSubstNo(LocalXPathSignatureLbl, 'FahrenheitToCelsiusResponse') +
LocalXPathSeparatorLbl + StrSubstNo(LocalXPathSignatureLbl,
'FahrenheitToCelsiusResult');
if DictionaryDefaultHeaders.ContainsKey('SOAPAction') then
DictionaryDefaultHeaders.Set('SOAPAction',
W3BaseNamespaceUriLbl + 'FahrenheitToCelsius');
end;
ConvertType::"To Farenheit":
begin
XMLElem := XmlElement.Create('CelsiusToFahrenheit',
W3BaseNamespaceUriLbl);
AddChildElementWithTxtValue(XMLElem, 'Celsius',
W3BaseNamespaceUriLbl, Format(Temperature));
ResultXPath := BodyXPathLbl + LocalXPathSeparatorLbl +
StrSubstNo(LocalXPathSignatureLbl, 'CelsiusToFahrenheitResponse') +
LocalXPathSeparatorLbl +
StrSubstNo(LocalXPathSignatureLbl, 'CelsiusToFahrenheitResult');
if DictionaryDefaultHeaders.ContainsKey('SOAPAction') then
DictionaryDefaultHeaders.Set('SOAPAction',
W3BaseNamespaceUriLbl + 'CelsiusToFahrenheit');
end;
end;
//Append body of request XMLElem to base request XML document
BaseXMLDoc.SelectSingleNode(BodyXPathLbl, BodyNode);
BodyNode.AsXmlElement().Add(XMLElem);
BaseXMLDoc.WriteTo(ContentToSend);
//Send request XML Document and write result to text variable
Result := SendTemperatureConversionAPIRequest(ContentToSend, ContentType,
DictionaryDefaultHeaders);
//Read result XML to find result temperature from ResultXPath
NewTemperature := GetValueFromXML(Result, ResultXPath);
//Handle error in case of success response status code (200)
if NewTemperature = ErrorLbl then
Error(ErrorLbl);
end;
local procedure SendTemperatureConversionAPIRequest(ContentToSend: Text;
ContentType: Text; DictionaryDefaultHeaders: Codeunit "Dictionary Wrapper"): Text
var
APIMgt: Codeunit "SDA API Mgt";
begin
exit(APIMgt.SendRequest(contentToSend, Enum::"Http Request Type"::POST,
W3BaseNamespaceUriLbl + W3ActionUriLbl,
ContentType, DictionaryDefaultHeaders));
end;
procedure CreateBaseXMLDoc(NamespacePrefix: Text; NamespaceUri: Text):
XmlDocument
var
XMLDoc: XmlDocument;
XMLDec: XmlDeclaration;
XMLElem: XmlElement;
XMLElem2: XmlElement;
XMLAtr: XmlAttribute;
begin
XMLDoc := XmlDocument.Create();
XMLDec := XmlDeclaration.Create('1.0', 'UTF-8', 'yes');
XMLDoc.SetDeclaration(XMLDec);
xmlElem := xmlElement.Create('Envelope', NamespaceUri);
XMLAtr := XmlAttribute.CreateNamespaceDeclaration('xsi',
'http://www.w3.org/2001/XMLSchema-instance');
XMLElem.Add(XMLAtr);
XMLAtr := XmlAttribute.CreateNamespaceDeclaration('xsd',
'http://www.w3.org/2001/XMLSchema');
XMLElem.Add(XMLAtr);
XMLAtr := XmlAttribute.CreateNamespaceDeclaration(NamespacePrefix,
NamespaceUri);
XMLElem.Add(XMLAtr);
xmlElem2 := XmlElement.Create('Header', NamespaceUri);
xmlElem.Add(xmlElem2);
Clear(xmlElem2);
xmlElem2 := XmlElement.Create('Body', NamespaceUri);
xmlElem2.Add(xmlText.Create(''));
xmlElem.Add(xmlElem2);
xmlDoc.Add(xmlElem);
exit(XMLDoc);
end;
local procedure AddChildElementWithTxtValue(var inXMLElem: XmlElement;
LocalName: Text; NamespaceUri: Text; inValue: Text);
var
CData: XmlCData;
begin
CData := XmlCData.Create('');
AddChildElementWithCdataTxtValue(inXMLElem, LocalName, NamespaceUri,
inValue, CData)
end;
local procedure AddChildElementWithCdataTxtValue(var inXMLElem: XmlElement;
LocalName: Text; NamespaceUri: Text; inValue: Text; CData: XmlCData)
var
XMLEelem: XmlElement;
begin
if NamespaceUri <> '' then
XMLEelem := XmlElement.Create(LocalName, NamespaceUri)
else
XMLEelem := XmlElement.Create(LocalName);
XMLEelem.Add(xmlText.Create(inValue));
if CData.Value() <> '' then
XMLEelem.Add(CData);
inXMLElem.Add(XMLEelem);
end;
procedure GetValueFromXML(Content: Text; pNodePath: Text): Text
var
XMLRootNode: XmlNode;
XMLChildNode: XmlNode;
XMLElem: XmlElement;
begin
GetRootNode(ConvertTextToXmlDocument(Content), XMLRootNode);
XMLRootNode.SelectSingleNode(pNodePath, XMLChildNode);
XMLElem := XMLChildNode.AsXmlElement();
exit(XMLElem.InnerText());
end;
procedure ConvertTextToXmlDocument(Content: Text): XmlDocument
var
XmlDoc: XmlDocument;
begin
if XmlDocument.ReadFrom(Content, XmlDoc) then
exit(XmlDoc);
end;
procedure GetRootNode(pXMLDocument: XmlDocument; var pFoundXMLNode: XmlNode)
var
lXmlElement: XmlElement;
begin
pXMLDocument.GetRoot(lXmlElement);
pFoundXMLNode := lXmlElement.AsXmlNode();
end;
var
SOAP11NamespaceURILbl: Label 'http://schemas.xmlsoap.org/soap/envelope/',
Locked = true;
SOAP12NamespaceUriLbl: Label 'http://www.w3.org/2003/05/soap-envelope',
Locked = true;
W3BaseNamespaceUriLbl: Label 'https://www.w3schools.com/xml/',
Locked = true;
SOAP11XMLContentTypeLbl: Label 'text/xml; charset=utf-8', Locked = true;
SOAP12XMLContentTypeLbl: Label 'application/soap+xml; charset=utf-8',
Locked = true;
W3ActionUriLbl: Label 'tempconvert.asmx', Locked = true;
LocalXPathSignatureLbl: Label '[local-name()="%1"]', Locked = true;
LocalXPathSeparatorLbl: Label '/*', Locked = true;
BodyXPathLbl: Label '/*[local-name()="Envelope"]/*[local-name()="Body"]',
Locked = true;
ErrorLbl: Label 'Error', Locked = true;
}
Like :xml
No comments:
Post a Comment