microsoft / AL

Home of the Dynamics 365 Business Central AL Language extension for Visual Studio Code. Used to track issues regarding the latest version of the AL compiler and developer tools available in the Visual Studio Code Marketplace or as part of the AL Developer Preview builds for Dynamics 365 Business Central.
MIT License
747 stars 245 forks source link

[BUG?]: foreach XmlNodeList the XmlNode from SelectSingleNode is not allocating correctly #4723

Open jakobkellett opened 5 years ago

jakobkellett commented 5 years ago

Describe the bug

I am calling a web service that returns the following XML:

<content>
    <read refname="accountquery" responsestatus="success">
       <activeaccounts>
         <id>ae4e36fe-ff19-4587-96ea-cdb7770efa32</id>
         <name>First Credit Account</name>
         <platformtype.name>Credit Card</platformtype.name>
       </activeaccounts>
       <activeaccounts>
         <id>75a0218f-e111-4b4a-9689-db1b5186b3b6</id>
         <name>Second Credit Account</name>
         <platformtype.name>Credit Card</platformtype.name>
       </activeaccounts>
    </read>
</content>

I have the following local variables:

CurrentMessage: Text;
LocalXmlDocument: XmlDocument;
LocalNode: XmlNode;
LocalValueNode: XmlNode;
LocalXmlElement: XmlElement;
LocalNodeList: XmlNodeList;

What is happening is the first iteration processes just fine, but on the second iteration of the foreach is acting strange. The LocalNode appears to allocate correctly, but the LocalNode.SelectSingleNode('//id', LocalValueNode) is grabbing the previous value of LocalNode for some reason.

To Reproduce Steps and/or AL code to reproduce the behavior:

I edited this to be a complete code block for execution.

trigger OnOpenPage();
    var
        XmlString: Text;
        Doc: XmlDocument;
        Node: XmlNode;
        NodeList: XmlNodeList;
        NewNode: XmlNode;
        Options: XmlReadOptions;
        Result: Text;
    begin
        Options.PreserveWhitespace := true;

        XmlString := '<content><read refname="accountquery" responsestatus="success"><activeaccounts><id>ae4e36fe-ff19-4587-96ea-cdb7770efa32</id><name>First Credit Account</name><platformtype.name>Credit Card</platformtype.name></activeaccounts><activeaccounts><id>75a0218f-e111-4b4a-9689-db1b5186b3b6</id><name>Second Credit Account</name><platformtype.name>Credit Card</platformtype.name></activeaccounts></read></content>';
        XmlDocument.ReadFrom(XmlString, Options, Doc);

        Doc.SelectNodes('//read[@refname="accountquery"]//activeaccounts', NodeList);

        if NodeList.Count() > 0
        then begin
            foreach Node in NodeList do begin
                Node.SelectSingleNode('//id', NewNode);
                Message(Node.AsXmlElement.InnerText);
                Message(NewNode.AsXmlElement.InnerText);
            end;
        end
        else begin
            Message('There were no accounts setup.')
        end;
    end;

Expected behavior The iteration should be setting LocalValueNode (XmlNode) to 75a0218f-e111-4b4a-9689-db1b5186b3b6 on the second iteration of the foreach LocalNodeList (XmlNodeList).

Screenshots If applicable, add screenshots to help explain your problem.

Iteration 1 - LocalNode WriteTo Text iteration-1-LocalNode

Iteration 1 - LocalValueNode WriteTo Text iteration-1-LocalValueNode

Iteration 1 - LocalXmlElement InnerText iteration-1-LocalXmlElement

Iteration 2 - LocalNode WriteTo Text iteration-2-LocalNode

Iteration 2 - LocalValueNode WriteTo Text iteration-2-LocalValueNode

Iteration 2 - LocalXmlElement InnerText iteration-2-LocalXmlElement

Versions:

jakobkellett commented 5 years ago

Hey @kalberes , I appreciate the labeling of the bug. Is there any updates by chance on this issue? We will be going to the Microsoft Directions Event in Early May (bought a booth!) and hoping we can convert our code from C/AL in time! Thank you~

xgaronnat commented 5 years ago

Hi, I found the same issue with this code in April '19 CU1 : Line is always giving the value of the first node(Line) only...

        XmlDoc.SelectNodes('//ShipmentItem', Lines);
        if Lines.Count > 0 then begin
            foreach Line in Lines do begin

                Line.SelectSingleNode('//ItemID/ID', XmlSubNode);
                ItemID := XmlSubNode.AsXmlElement().InnerText;

                Line.SelectSingleNode('//ShippedQuantity', XmlSubNode);
                ShippedQty := XmlSubNode.AsXmlElement().InnerText;

                Line.SelectSingleNode('//LineNumber', XmlSubNode);
                LineNumber := XmlSubNode.AsXmlElement().InnerText;

                message('Line\Item ID = %1\Shipped Qty = %2\Line Number = %3',
                    ItemID,
                    ShippedQty,
                    LineNumber)
            end;
        end;
xgaronnat commented 5 years ago

Indeed it's working : use ./ItemID/ID for find the node in the current Line.

ahelwig commented 4 years ago

Replacing the "/" or "//" at the start of each XPath string with the context item expression "." followed by the "/" or "//" did the trick. Glad I found your post.

MortenRa commented 3 years ago

@atoader Is this going to be looked into

atoader commented 3 years ago

Yes, but I cannot provide an ETA. We have a large number of issues reported through GitHub. We will work on prioritizing issues based on severity and input from developers in the next couple of weeks. We should have an update soon.