XMLPort Export - modifying Node Name

I have an XMLPort. Before it is outputted to a file and/or stream, I want to modify some node names. Is there a trigger that gives me access to the actual XML node?

Specific use case is, I'm trying to create an XMLPort where there is a node called <action> . I've tried to set the Node Name to action (Node Type element, Source Type text), but it will not let me do that because "action" is a reserved word. (ACTION.ok, etc).

Best Answer

Answers

  • halcyon1234halcyon1234 Member Posts: 8
    Hi, Jan, thank you for the reply.

    The Node is type Element of Text, so there isn't a Data Source field. The Data Source becomes the Node Name, which is "action". So you're right, that would work for the case when the Data Source = Record."Action".

    So far, I've been working on a solution where, after the XMLPort is done, it will iterate through the document, find elements named action_1, and rename them to action. It's based partially on the "skip empty node" thread from this forum. I will post the final solution once it is tested.

    http://forum.mibuso.com/discussion/18042/xmlport-skip-empty-tags
  • halcyon1234halcyon1234 Member Posts: 8
    Here is the solution I came up with
        PROCEDURE RenameElements@1101757001(XMLNode@1101757000 : Automation "{F5078F18-C551-11D3-89B9-0000F81FE221} 3.0:{2933BF80-7B36-11D2-B20E-00C04F983E60}:'Microsoft XML, v3.0'.IXMLDOMNode";OldNodeName@1000000000 : Text[200];NewNodeName@1000000001 : Text[200]) result : Boolean;
        VAR
          XMLChildNode@1101757001 : Automation "{F5078F18-C551-11D3-89B9-0000F81FE221} 3.0:{2933BF80-7B36-11D2-B20E-00C04F983E60}:'Microsoft XML, v3.0'.IXMLDOMNode";
          XMLDomNodeList@1101757002 : Automation "{F5078F18-C551-11D3-89B9-0000F81FE221} 3.0:{2933BF82-7B36-11D2-B20E-00C04F983E60}:'Microsoft XML, v3.0'.IXMLDOMNodeList";
          XMLDomDocument@1101757004 : Automation "{F5078F18-C551-11D3-89B9-0000F81FE221} 3.0:{F6D90F11-9C73-11D3-B32E-00C04F990BB4}:'Microsoft XML, v3.0'.DOMDocument";
          i@1101757005 : Integer;
          NewXMLNode@1101757003 : Automation "{F5078F18-C551-11D3-89B9-0000F81FE221} 3.0:{2933BF80-7B36-11D2-B20E-00C04F983E60}:'Microsoft XML, v3.0'.IXMLDOMNode";
          NewParentNode@1101757006 : Automation "{F5078F18-C551-11D3-89B9-0000F81FE221} 3.0:{2933BF80-7B36-11D2-B20E-00C04F983E60}:'Microsoft XML, v3.0'.IXMLDOMNode";
          TempChildNode@1101757007 : Automation "{F5078F18-C551-11D3-89B9-0000F81FE221} 3.0:{2933BF80-7B36-11D2-B20E-00C04F983E60}:'Microsoft XML, v3.0'.IXMLDOMNode";
          NodeAttributes@1101757008 : Automation "{F5078F18-C551-11D3-89B9-0000F81FE221} 3.0:{2933BF83-7B36-11D2-B20E-00C04F983E60}:'Microsoft XML, v3.0'.IXMLDOMNamedNodeMap";
          CurrentXMLNodeForAttribute@1101757009 : Automation "{F5078F18-C551-11D3-89B9-0000F81FE221} 3.0:{2933BF80-7B36-11D2-B20E-00C04F983E60}:'Microsoft XML, v3.0'.IXMLDOMNode";
        BEGIN
          // Recursively rename elements in a document
    
    
          // Only rename nodes that are of type Element (maybe expand this later to also do attributes)
          IF XMLNode.nodeTypeString = 'element' THEN
          BEGIN
            // If the node has the name that we're trying to replace
            IF UPPERCASE(XMLNode.nodeName) = UPPERCASE(OldNodeName) THEN
            BEGIN
    
              // Create a brand new node in this document.  We will copy the old node's attributes, value and children over
              // And then delete the old node
              XMLDomDocument := XMLNode.ownerDocument();
              NewXMLNode := XMLDomDocument.createNode(XMLNode.nodeType, NewNodeName, XMLNode.namespaceURI);
    
    
              // Move over child nodes.  Append removes the child from the old node
              WHILE (XMLNode.hasChildNodes) DO
              BEGIN
                  TempChildNode := XMLNode.firstChild();
                  NewXMLNode.appendChild(TempChildNode);
    
              END;
    
              // copy over attributes
              // Remember, must REMOVE from old node before Setting in new node
              NodeAttributes := XMLNode.attributes();
              WHILE NodeAttributes.length > 0 DO
              BEGIN
                  CurrentXMLNodeForAttribute := NodeAttributes.item(i);
                  NodeAttributes.removeNamedItem(CurrentXMLNodeForAttribute.nodeName);
                  NewXMLNode.attributes.setNamedItem(CurrentXMLNodeForAttribute);
    
              END;
    
              // Get a reference to this node's parent, and swap the old node for the new node
              // NOTE:  What happens when you rename root element? UNTESTED
              NewParentNode := XMLNode.parentNode;
              NewParentNode.replaceChild(NewXMLNode, XMLNode);
    
              // Finally, replace the reference so the recursive function will work
              XMLNode := NewXMLNode;
            END;
    
            // If this element has children, recurse through them to check for more renaming
            IF (XMLNode.hasChildNodes) THEN
            BEGIN
                XMLDomNodeList := XMLNode.childNodes;
                FOR i := 1 TO XMLDomNodeList.length DO
                BEGIN
                  XMLChildNode :=XMLDomNodeList.nextNode();
                  RenameElements(XMLChildNode, OldNodeName, NewNodeName);
                END;
            END;
          END;
    
          result := TRUE;
        END;
    
    

    Call it by getting the root of your XML document with .documentElement, and call RenameElements(rootnode, 'old_element_name', 'new_element_name')
  • Jan_VeenendaalJan_Veenendaal Member Posts: 206
    Have you even tried? I tested my solution in NAV 2009 R2 and in NAV 2016 - both work fine.

    cbb6pn5233bm.jpg

    Jan Veenendaal
  • halcyon1234halcyon1234 Member Posts: 8
    Ah, I see how the DataSource has changed. Apologies, I had passed the solution onto another developer, who told me it didn't work-- but I see they didn't modify the datasource to be "actiontest".

    Well, at least I learned a bunch about DOM manipulation in C/AL code. =)
Sign In or Register to comment.