VS Code XML DOM Management – Part 2

In the previous post, I have published only few set of functions related to XML DOM Management.

Here is a set of additional functions which could be useful when working with XML. It is not fully tested though, In case any issues in the function, please let me know. Hope this helps. Thanks

codeunit 50100 "XML DOM Mgt."
{
    trigger OnRun();
    begin
    end;

    procedure AddElement(var pXMLNode: XmlNode; pNodeName: Text; pNodeText: Text; pNameSpace: Text; var pCreatedNode: XmlNode): Boolean
    var
        lNewChildNode: XmlNode;
    begin
        if pNodeText <> '' then
            lNewChildNode := XmlElement.Create(pNodeName, pNameSpace, pNodeText).AsXmlNode()
        else
            lNewChildNode := XmlElement.Create(pNodeName, pNameSpace).AsXmlNode();
        if pXMLNode.AsXmlElement().Add(lNewChildNode) then begin
            pCreatedNode := lNewChildNode;
            exit(true);
        end;
    end;

    procedure AddRootElement(var pXMLDocument: XmlDocument; pNodeName: Text; var pCreatedNode: XmlNode): Boolean
    begin
        pCreatedNode := XmlElement.Create(pNodeName).AsXmlNode();
        exit(pXMLDocument.Add(pCreatedNode));
    end;

    procedure AddRootElementWithPrefix(var pXMLDocument: XmlDocument; pNodeName: Text; pPrefix: Text; pNameSpace: text; var pCreatedNode: XmlNode): Boolean
    begin
        pCreatedNode := XmlElement.Create(pNodeName, pNameSpace).AsXmlNode();
        pCreatedNode.AsXmlElement().Add(XmlAttribute.CreateNamespaceDeclaration(pPrefix, pNameSpace));
        exit(pXMLDocument.Add(pCreatedNode));
    end;

    procedure AddElementWithPrefix(var pXMLNode: XmlNode; pNodeName: Text; pNodeText: Text; pPrefix: Text; pNameSpace: text; var pCreatedNode: XmlNode): Boolean
    var
        lNewChildNode: XmlNode;
    begin
        if pNodeText <> '' then
            lNewChildNode := XmlElement.Create(pNodeName, pNameSpace, pNodeText).AsXmlNode()
        else
            lNewChildNode := XmlElement.Create(pNodeName, pNameSpace).AsXmlNode();
        lNewChildNode.AsXmlElement().Add(XmlAttribute.CreateNamespaceDeclaration(pPrefix, pNameSpace));
        if pXMLNode.AsXmlElement().Add(lNewChildNode) then begin
            pCreatedNode := lNewChildNode;
            exit(true);
        end;
    end;

    procedure AddPrefix(var pXMLNode: XmlNode; pPrefix: Text; pNameSpace: text): Boolean
    begin
        pXMLNode.AsXmlElement().Add(XmlAttribute.CreateNamespaceDeclaration(pPrefix, pNameSpace));
        exit(true);
    end;

    procedure AddAttribute(var pXMLNode: XmlNode; pName: Text; pValue: Text): Boolean
    begin
        pXMLNode.AsXmlElement().SetAttribute(pName, pValue);
        exit(true);
    end;

    procedure AddAttributeWithNamespace(var pXMLNode: XmlNode; pName: Text; pNameSpace: text; pValue: Text): Boolean
    begin
        pXMLNode.AsXmlElement().SetAttribute(pName, pNameSpace, pValue);
        exit(true);
    end;

    procedure FindNode(pXMLRootNode: XmlNode; pNodePath: Text; var pFoundXMLNode: XmlNode): Boolean
    begin
        exit(pXMLRootNode.SelectSingleNode(pNodePath, pFoundXMLNode));
    end;

    procedure FindNodeWithNameSpace(pXMLRootNode: XmlNode; pNodePath: Text; pPrefix: Text; pNamespace: Text; var pFoundXMLNode: XmlNode): Boolean
    var
        lXmlNsMgr: XmlNamespaceManager;
        lXMLDocument: XmlDocument;
    begin

        if pXMLRootNode.IsXmlDocument() then
            lXmlNsMgr.NameTable(pXMLRootNode.AsXmlDocument().NameTable())
        else begin
            pXMLRootNode.GetDocument(lXMLDocument);
            lXmlNsMgr.NameTable(lXMLDocument.NameTable());
        end;
        lXMLNsMgr.AddNamespace(pPrefix, pNamespace);
        exit(pXMLRootNode.SelectSingleNode(pNodePath, lXmlNsMgr, pFoundXMLNode));
    end;

    procedure FindNodesWithNameSpace(pXMLRootNode: XmlNode; pXPath: Text; pPrefix: Text; pNamespace: Text; var pFoundXmlNodeList: XmlNodeList): Boolean
    var
        lXmlNsMgr: XmlNamespaceManager;
        lXMLDocument: XmlDocument;
    begin
        if pXMLRootNode.IsXmlDocument() then
            lXmlNsMgr.NameTable(pXMLRootNode.AsXmlDocument().NameTable())
        else begin
            pXMLRootNode.GetDocument(lXMLDocument);
            lXmlNsMgr.NameTable(lXMLDocument.NameTable());
        end;
        lXMLNsMgr.AddNamespace(pPrefix, pNamespace);
        exit(FindNodesWithNamespaceManager(pXMLRootNode, pXPath, lXmlNsMgr, pFoundXmlNodeList));
    end;

    procedure FindNodesWithNamespaceManager(pXMLRootNode: XmlNode; pXPath: Text; pXmlNsMgr: XmlNamespaceManager; var pFoundXmlNodeList: XmlNodeList): Boolean
    begin
        if not pXMLRootNode.SelectNodes(pXPath, pXmlNsMgr, pFoundXmlNodeList) then
            exit(false);
        if pFoundXmlNodeList.Count() = 0 then
            exit(false);
        exit(true);
    end;

    procedure FindNodeXML(pXMLRootNode: XmlNode; pNodePath: Text): Text
    var
        lFoundXMLNode: XmlNode;
    begin
        if pXMLRootNode.SelectSingleNode(pNodePath, lFoundXMLNode) then
            exit(lFoundXMLNode.AsXmlElement().InnerXml());
    end;

    procedure FindNodeText(pXMLRootNode: XmlNode; pNodePath: Text): Text
    var
        lFoundXMLNode: XmlNode;
    begin
        if pXMLRootNode.SelectSingleNode(pNodePath, lFoundXMLNode) then
            exit(lFoundXMLNode.AsXmlElement().InnerText());
    end;

    procedure FindNodeTextWithNameSpace(pXMLRootNode: XmlNode; pNodePath: Text; pPrefix: Text; pNamespace: Text): Text
    var
        lXmlNsMgr: XmlNamespaceManager;
        lXMLDocument: XmlDocument;
    begin

        if pXMLRootNode.IsXmlDocument() then
            lXmlNsMgr.NameTable(pXMLRootNode.AsXmlDocument().NameTable())
        else begin
            pXMLRootNode.GetDocument(lXMLDocument);
            lXmlNsMgr.NameTable(lXMLDocument.NameTable());
        end;
        lXMLNsMgr.AddNamespace(pPrefix, pNamespace);
        exit(FindNodeTextNs(pXMLRootNode, pNodePath, lXmlNsMgr));
    end;

    procedure FindNodeTextNs(pXMLRootNode: XmlNode; pNodePath: Text; pXmlNsMgr: XmlNamespaceManager): Text
    var
        lFoundXMLNode: XmlNode;
    begin
        if pXMLRootNode.SelectSingleNode(pNodePath, pXmlNsMgr, lFoundXMLNode) then
            exit(lFoundXMLNode.AsXmlElement().InnerText());
    end;

    procedure FindNodes(pXMLRootNode: XmlNode; pNodePath: Text; var pFoundXMLNodeList: XmlNodeList): Boolean
    begin
        if not pXMLRootNode.SelectNodes(pNodePath, pFoundXmlNodeList) then
            exit(false);
        if pFoundXmlNodeList.Count() = 0 then
            exit(false);
        exit(true);
    end;

    procedure GetRootNode(pXMLDocument: XmlDocument; var pFoundXMLNode: XmlNode): Boolean
    var
        lXmlElement: XmlElement;
    begin
        pXMLDocument.GetRoot(lXmlElement);
        pFoundXMLNode := lXmlElement.AsXmlNode();
    end;

    procedure FindAttribute(pXMLNode: XmlNode; var pXmlAttribute: XmlAttribute; pAttributeName: Text): Boolean
    begin
        exit(pXMLNode.AsXmlElement().Attributes().Get(pAttributeName, pXmlAttribute));
    end;

    procedure GetAttributeValue(pXMLNode: XmlNode; pAttributeName: Text): Text
    var
        lXmlAttribute: XmlAttribute;
    begin
        if pXMLNode.AsXmlElement().Attributes().Get(pAttributeName, lXmlAttribute) then
            exit(lXmlAttribute.Value());
    end;

    procedure AddDeclaration(var pXMLDocument: XmlDocument; pVersion: Text; pEncoding: Text; pStandalone: Text)
    var
        lXmlDeclaration: XmlDeclaration;
    begin
        lXmlDeclaration := XmlDeclaration.Create(pVersion, pEncoding, pStandalone);
        pXMLDocument.SetDeclaration(lXmlDeclaration);
    end;

    procedure AddGroupNode(var pXMLNode: XmlNode; pNodeName: Text)
    var
        lXMLNewChild: XmlNode;
    begin
        AddElement(pXMLNode, pNodeName, '', '', lXMLNewChild);
        pXMLNode := lXMLNewChild;
    end;

    procedure AddNode(var pXMLNode: XmlNode; pNodeName: Text; pNodeText: Text)
    var
        lXMLNewChild: XmlNode;
    begin
        AddElement(pXMLNode, pNodeName, pNodeText, '', lXMLNewChild);
    end;

    procedure AddLastNode(var pXMLNode: XmlNode; pNodeName: Text; pNodeText: Text)
    var
        lXMLNewChild: XmlNode;
        lXMLElement: XmlElement;
    begin
        AddElement(pXMLNode, pNodeName, pNodeText, '', lXMLNewChild);
        if pXMLNode.GetParent(lXMLElement) then
            pXMLNode := lXMLElement.AsXmlNode();
    end;

    procedure GetXmlNSMgr(pXMLRootNode: XmlNode; pPrefix: Text; pNamespace: Text; var pXmlNsMgr: XmlNamespaceManager): Text
    var
        lXMLDocument: XmlDocument;
    begin

        if pXMLRootNode.IsXmlDocument() then
            pXmlNsMgr.NameTable(pXMLRootNode.AsXmlDocument().NameTable())
        else begin
            pXMLRootNode.GetDocument(lXMLDocument);
            pXmlNsMgr.NameTable(lXMLDocument.NameTable());
        end;
        pXmlNsMgr.AddNamespace(pPrefix, pNamespace);
    end;

    procedure AddNameSpace(var pXmlNsMgr: XmlNamespaceManager; pPrefix: text; pNamespace: text);
    begin
        pXmlNsMgr.AddNamespace(pPrefix, pNamespace);
    end;

    procedure AddNamespaces(var pXmlNsMgr: XmlNamespaceManager; pXMLDocument: XmlDocument)
    var
        lXmlAttributeCollection: XmlAttributeCollection;
        lXmlAttribute: XmlAttribute;
        lXMLElement: XmlElement;
    begin
        pXmlNsMgr.NameTable(pXMLDocument.NameTable());
        pXMLDocument.GetRoot(lXMLElement);
        lXmlAttributeCollection := lXMLElement.Attributes();
        if lXMLElement.NamespaceUri() <> '' then
            pXmlNsMgr.AddNamespace('', lXMLElement.NamespaceUri());
        Foreach lXmlAttribute in lXmlAttributeCollection do
            if StrPos(lXmlAttribute.Name(), 'xmlns:') = 1 then
                pXmlNsMgr.AddNamespace(DELSTR(lXmlAttribute.Name(), 1, 6), lXmlAttribute.Value());
    end;

    procedure XMLEscape(pText: Text): Text
    var
        lXMLDocument: XmlDocument;
        lRootXmlNode: XmlNode;
        lXmlNode: XmlNode;
    begin
        lXMLDocument := XmlDocument.Create();
        AddElement(lRootXmlNode, 'XMLEscape', pText, '', lXmlNode);
        exit(lXmlNode.AsXmlElement().InnerXml());
    end;

    procedure LoadXMLDocumentFromText(pXMLText: Text; var pXMLDocument: XmlDocument)
    begin
        if pXMLText = '' then
            exit;
        XmlDocument.ReadFrom(pXMLText, pXMLDocument);
    end;

    procedure LoadXMLNodeFromText(pXMLText: Text; var pXMLNode: XmlNode)
    var
        lXmlDocument: XmlDocument;
    begin
        LoadXMLDocumentFromText(pXMLText, lXmlDocument);
        pXMLNode := lXmlDocument.AsXmlNode();
    end;

    procedure LoadXMLDocumentFromInStream(pInStream: InStream; var pXMLDocument: XmlDocument)
    begin
        XmlDocument.ReadFrom(pInStream, pXMLDocument);
    end;

    procedure LoadXMLNodeFromInStream(pInStream: InStream; var pXMLNode: XmlNode)
    var
        lXmlDocument: XmlDocument;
    begin
        LoadXMLDocumentFromInStream(pInStream, lXmlDocument);
        pXMLNode := lXmlDocument.AsXmlNode();
    end;

    procedure RemoveNamespaces(pXmlText: Text): Text
    var
        XMLDOMMgt: Codeunit "XML DOM Management";
    begin
        exit(XMLDOMMgt.RemoveNamespaces(pXmlText));
    end;

    procedure SetUTF88Declaration(var pXMLDocument: XmlDocument; pStandaloneTxt: Text);
    var
        lXmlDeclaration: XmlDeclaration;
    begin
        lXmlDeclaration := XmlDeclaration.Create('1.0', 'utf-8', pStandaloneTxt);
        pXMLDocument.SetDeclaration(lXmlDeclaration);
    end;

    procedure ReplaceInvalidXMLCharacters(pText: Text): Text
    var
        lText: Text;
    begin
        lText := pText;
        lText := lText.Replace('&', '&amp;');
        lText := lText.Replace('<', '&lt;');
        lText := lText.Replace('>', '&gt;');
        lText := lText.Replace('"', '&quot;');
        lText := lText.Replace('''', '&apos;');
        exit(lText);
    end;

    procedure RemoveXMLRestrictedCharacters(pXmlText: Text): Text
    var
        lXmlText: Text;
        lChar: array[30] of Char;
        lArrayLen: Integer;
        li: Integer;
    begin

        if pXmlText = '' then
            exit(pXmlText);

        lXmlText := pXmlText;

        lChar[1] := 1;
        lChar[2] := 2;
        lChar[3] := 3;
        lChar[4] := 4;
        lChar[5] := 5;
        lChar[6] := 6;
        lChar[7] := 7;
        lChar[8] := 8;
        lChar[9] := 11;
        lChar[10] := 12;
        lChar[11] := 14;
        lChar[12] := 15;
        lChar[13] := 16;
        lChar[14] := 17;
        lChar[15] := 18;
        lChar[16] := 19;
        lChar[17] := 20;
        lChar[18] := 21;
        lChar[19] := 22;
        lChar[20] := 23;
        lChar[21] := 24;
        lChar[22] := 25;
        lChar[23] := 26;
        lChar[24] := 27;
        lChar[25] := 28;
        lChar[26] := 29;
        lChar[27] := 30;
        lChar[28] := 31;
        lChar[29] := 127;

        lArrayLen := ArrayLen(lChar);
        for li := 1 to lArrayLen do
            lXmlText := DelChr(lXmlText, '=', lChar[li]);
        exit(lXmlText);
    end;
}

 

Advertisements

9 thoughts on “VS Code XML DOM Management – Part 2

  1. Thank’s Divesh for taking your time with this. It saved me some time!

    I added this to be able to add more namespaces to my root element:

    procedure AddPrefix(var pXMLNode: XmlNode; pPrefix: Text; pNameSpace: text): Boolean
    begin
    pXMLNode.AsXmlElement.Add(XmlAttribute.CreateNamespaceDeclaration(pPrefix, pNameSpace));
    exit(true);
    end;

    Like

  2. Pingback: AL and SOAP | larswestman.se

  3. Pingback: Creating Soap Request Message in AL | Divesh Bora – MSD NAV Blog

  4. Pingback: Creating Soap Request Message in AL - Microsoft Dynamics NAV Community

  5. Hi Divesh,
    I am working on API and wrote code in CAL for accessing each XML tag value. But now I want to write code in AL, but don’t know how to write. Please help me:

    **My XML Content [XmlText] snippet:**

    https://www.mywebsite.com/
    0_YdG/DRSVGCKyy6fx/fdasdY6avs=
    05/28/2019 11:50:14 PM
    0_i1G4fADRTVRDfdsac4GjD5R5UoOPks

    For reference you can look into my previous CAL code:
    **getToken(XmlText : Text) : Text**
    XmlDocument:=XmlDocument.XmlDocument;
    XmlDocument.LoadXml(XmlText);
    XMLNodeList := XmlDocument.GetElementsByTagName(‘Access_Token’);
    count:=XMLNodeList.Count;

    //First for loop to iterate the Access_Token Node– START
    FOR I := 0 TO count – 1 DO BEGIN
    DOMNode := XMLNodeList.Item(I);
    TempXMLNodeList:= DOMNode.ChildNodes;
    childcount:= TempXMLNodeList.Count;
    DOMChildNode:=TempXMLNodeList.Item(I);
    FOR J := 0 TO childcount – 1 DO BEGIN
    DOMChildNode:=TempXMLNodeList.Item(J);
    IF ( FORMAT(DOMChildNode.NodeType)=’Text’ ) OR ( FORMAT(DOMChildNode.NodeType)=’Element’ ) THEN BEGIN
    CurrentElementName:=DOMChildNode.Name;
    IF CurrentElementName = ‘Instance_Url’ THEN BEGIN
    Instance_URL := DOMChildNode.InnerText;
    END
    ELSE IF CurrentElementName = ‘YourToken’ THEN BEGIN
    TOKEN := DOMChildNode.InnerText;
    END
    ELSE IF CurrentElementName = ‘Expiration_date’ THEN BEGIN
    Expiration_date := DOMChildNode.InnerText;
    END
    ELSE IF CurrentElementName = ‘Refresh_Token’ THEN BEGIN
    Refresh_Token := DOMChildNode.InnerText;
    END
    END; // END of major If condition
    END; //Second for loop to iterate the child nodes Access_Token Node — END
    END;//First for loop to iterate the Parent or first node : Access_Token Node — END

    Thanks in Advance.

    Please tell or share code to read XML node values in AL, Most of the Features are not working.

    Like

    • Hi Tabrez,

      Below is the example to read xml in AL as per your requirement.

      codeunit 50101 “Read Xml”
      {
      trigger OnRun()
      var
      lXmlText: Text;
      begin
      lXmlText := ”;
      lXmlText += ”;
      lXmlText += ‘URl1’;
      lXmlText += ”;
      lXmlText += ‘TOKEN 1’;
      lXmlText += ”;
      lXmlText += ”;

      lXmlText += ”;
      lXmlText += ‘URl2’;
      lXmlText += ”;
      lXmlText += ‘TOKEN 2’;
      lXmlText += ”;
      lXmlText += ”;

      lXmlText += ”;
      lXmlText += ‘URL21’;
      lXmlText += ”;
      lXmlText += ‘TOKEN 21’;
      lXmlText += ”;
      lXmlText += ”;

      lXmlText += ”;
      ReadXml(lXmlText);
      end;

      local procedure ReadXml(pXmlText: Text);
      var
      XmlDOMMgt: Codeunit “XML DOM Mgt.”;
      lXmlDocument: XmlDocument;
      lXmlRootNode: XmlNode;
      lAccessTokenList: XmlNodeList;
      lNodeList: XmlNodeList;
      lXMLNode: XmlNode;
      lTempNode: XmlNode;
      begin
      XmlDOMMgt.LoadXMLDocumentFromText(pXmlText, lXmlDocument);
      XmlDOMMgt.GetRootNode(lXmlDocument, lXmlRootNode);
      if not XmlDOMMgt.FindNodes(lXmlRootNode, ‘Access_Token’, lAccessTokenList) then
      error(‘Node Access_Token not found’);
      foreach lXMLNode in lAccessTokenList do begin
      lNodeList := lXMLNode.AsXmlElement().GetChildNodes();
      foreach lTempNode in lNodeList do
      case lTempNode.AsXmlElement().Name() of
      ‘Instance_Url’:
      Message(lTempNode.AsXmlElement().InnerText());
      ‘YourToken’:
      Message(lTempNode.AsXmlElement().InnerText());
      end;
      end;
      end;
      }

      Hope this helps. Please like and share the post if you think it helped. Thanks

      Like

  6. Hi Divesh,

    We need to write the code in AL to load the xml file saved on server. In CAL the Code is like :
    procedure ReadPackageHeader(DecompressedFileName: Text)
    var
    XMLDOMManagement: Codeunit “XML DOM Management”;
    PackageXML: DotNet XmlDocument;
    begin
    if “Package File Name” ” then begin
    XMLDOMManagement.LoadXMLDocumentFromFile(DecompressedFileName,PackageXML);
    ReadPackageHeaderCommon(PackageXML);
    end else begin
    “Package Code” := ”;
    “Package Name” := ”;
    “Product Version” := ”;
    “Language ID” := 0;
    end;
    end;
    local procedure ReadPackageHeaderCommon(PackageXML: DotNet XmlDocument)
    var
    ConfigPackage: Record “Config. Package”;
    ConfigXMLExchange: Codeunit “Config. XML Exchange”;
    DocumentElement: DotNet XmlElement;
    LanguageID: Text;
    begin
    DocumentElement := PackageXML.DocumentElement;
    “Package Code” :=
    CopyStr(
    ConfigXMLExchange.GetAttribute(
    ConfigXMLExchange.GetElementName(ConfigPackage.FieldName(Code)),DocumentElement),
    1,MaxStrLen(“Package Code”));
    if “Package Code” = ” then
    Error(PackageDataNotDefinedErr,FieldCaption(“Package Code”));
    “Package Name” :=
    CopyStr(
    ConfigXMLExchange.GetAttribute(
    ConfigXMLExchange.GetElementName(ConfigPackage.FieldName(“Package Name”)),DocumentElement),
    1,MaxStrLen(“Package Name”));
    if “Package Name” = ” then
    Error(PackageDataNotDefinedErr,FieldCaption(“Package Name”));
    “Product Version” :=
    CopyStr(
    ConfigXMLExchange.GetAttribute(
    ConfigXMLExchange.GetElementName(ConfigPackage.FieldName(“Product Version”)),DocumentElement),
    1,MaxStrLen(“Product Version”));
    LanguageID := ConfigXMLExchange.GetAttribute(
    ConfigXMLExchange.GetElementName(ConfigPackage.FieldName(“Language ID”)),DocumentElement);
    if LanguageID ” then
    Evaluate(“Language ID”,LanguageID);
    Modify;
    end;
    I have tried the XmlDocument.ReadFrom but it is only useful when i have the xml in text variable. May i know to how we can load the xml files in AL programming.
    Thanks in Advance.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s