Load Accounting Trade via Excel - Implementation Details

The main method 'LoadData' is called on clicking SUBMIT button. It initiates construction of the XML document and the loading process:

Sub LoadData() Dim ServerURL As String Dim Login As String Dim Pass As String Dim composedObject As String ServerURL = Range("B5").Text Login = Range("B6").Text Pass = ActiveSheet.TextBox1.Text composedObject = ComposeXML().XML If Login <> "" And Pass <> "" Then LoadAndRetrieveTSR ServerURL, Login, Pass, composedObject Else MsgBox "Invalid authorization!" End If End Sub

It calls the 'ComposeXML' function to compose an XML document, based on the filled fields of the AccountingTrade objects:

'Composes an XML documents based on the non-empty fields of the hierarchal representation of the AccountingTrade object Function ComposeXML() As MSXML2.DOMDocument 'A document to compose Dim document As MSXML2.DOMDocument Set document = New MSXML2.DOMDocument Dim mainNode As MSXML2.IXMLDOMNode Set mainNode = document.createElement("accountingTrade") document.appendChild mainNode 'Add identifiers Dim tempNode As MSXML2.IXMLDOMNode Set tempNode = document.createElement("objectType") tempNode.appendChild document.createTextNode("AccountingTrade") mainNode.appendChild tempNode Set tempNode = document.createElement("objectId") tempNode.appendChild document.createTextNode("AccountingTrade") mainNode.appendChild tempNode Set tempNode = document.createElement("objectDescription") tempNode.appendChild document.createTextNode("ACCOUNTING") mainNode.appendChild tempNode Dim mainSheet As Object Set mainSheet = ActiveWorkbook.Sheets(1) Dim lastFilterRow As Long lastFilterRow = mainSheet.Cells(Rows.Count, 1).End(xlUp).Row Dim curPath As String curPath = "" Dim i As Integer For i = 15 To lastFilterRow - 1 Dim curName As String curName = mainSheet.Cells(i, 1) If StrComp(Mid(curName, 1, 2), "</", vbTextCompare) = 0 Then curPath = Mid(curPath, 1, InStrRev(curPath, "/", -1, vbTextCompare) - 1) Else If StrComp(Mid(curName, 1, 1), "<", vbTextCompare) = 0 Then curPath = curPath & "/" & Mid(curName, 2, Len(curName) - 2) Else If Len(curName) > 0 And Len(mainSheet.Cells(i, 2)) > 0 Then Dim curValue As String curValue = mainSheet.Cells(i, 2) InsertNodeIntoDocument document, curPath & "/" & curName, curValue End If End If End If Next i Set ComposeXML = document End Function

Each created node is inserted using its path from document's root, a name and a value, if the value is not empty, by means of the 'InsertNodeIntoDocument' method:

Sub InsertNodeIntoDocument(doc As MSXML2.DOMDocument, path As String, value As String) Dim PathParts() As String PathParts = Split(path, "/", -1, vbTextCompare) Dim curPos As MSXML2.IXMLDOMElement Set curPos = doc.FirstChild Dim i As Integer Dim lastElemInd As Integer lastElemInd = UBound(PathParts) For i = 1 To lastElemInd - 1 Dim list As collection Set list = getImmediateChildrenByName(curPos, PathParts(i)) If list.Count > 0 Then Set curPos = list.Item(1) Else Dim newNode As MSXML2.IXMLDOMElement Set newNode = doc.createElement(PathParts(i)) curPos.appendChild newNode Set curPos = newNode End If Next i Set newNode = doc.createElement(PathParts(lastElemInd)) curPos.appendChild newNode Set curPos = newNode Dim valueNode As MSXML2.IXMLDOMText Set valueNode = doc.createTextNode(value) curPos.appendChild valueNode End Sub

'getImmediateChildrenByName' function is used to get immediate child nodes of the specified node, with a specified name:

Function getImmediateChildrenByName(elem As MSXML2.IXMLDOMElement, name As String) As collection Dim res As collection Set res = New collection Dim list As MSXML2.IXMLDOMNodeList Set list = elem.ChildNodes Dim length As Integer length = list.length Dim i As Integer For i = 0 To length - 1 If list.Item(i).NodeType = NODE_ELEMENT And StrComp(list.Item(i).nodeName, name, vbTextCompare) = 0 Then res.Add list.Item(i) End If Next i Set getImmediateChildrenByName = res End Function

After an XML document is composed, the 'LoadAndRetrieveTSR' method is called to initiate loading process and to retrieve the TSR:

Sub LoadAndRetrieveTSR(url As String, Login As String, Pass As String, composedObject As String) Dim sEnv As String Dim sRTR As String sRTR = "<EagleML xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xsi:type=""LoadAccounting"" eaglemlVersion=""2-0"" actualBuild=""1"" xmlns=""http://www.eagleinvsys.com/2011/EagleML-2-0"">" sRTR = sRTR & "<header xmlns=""http://www.eagleinvsys.com/2011/EagleML-2-0"">" sRTR = sRTR & "<messageId>" & Format(Now(), "yyyymmddThhmmss") & "</messageId>" sRTR = sRTR & "<sentBy>http://client.com</sentBy>" sRTR = sRTR & "<sendTo>http://www.eagleinvsys.com/eagle_ml-2-0_default_cm_control_message</sendTo>" sRTR = sRTR & "</header>" sRTR = sRTR & "<taskIdentifier>" sRTR = sRTR & "<correlationId>" & Format(Now(), "yyyymmddThhmmss") & "</correlationId>" sRTR = sRTR & "<businessTaskId>LoadAccountingTrade</businessTaskId>" sRTR = sRTR & "</taskIdentifier>" sRTR = sRTR & "<taskTypeEnum>LOAD</taskTypeEnum>" sRTR = sRTR & "<synchronousExecution>yes</synchronousExecution>" sRTR = sRTR & "<accountingTransaction>" sRTR = sRTR & composedObject sRTR = sRTR & "</accountingTransaction>" sRTR = sRTR & "</EagleML>" sEnv = "<?xml version=""1.0"" encoding=""utf-8""?>" sEnv = sEnv & "<s:Envelope xmlns:s=""http://schemas.xmlsoap.org/soap/envelope/"">" sEnv = sEnv & " <s:Body xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">" sEnv = sEnv & " <accountingTransactionMessage>" sEnv = sEnv & sRTR sEnv = sEnv & " </accountingTransactionMessage>" sEnv = sEnv & " </s:Body>" sEnv = sEnv & "</s:Envelope>" ContinueLoad sEnv, url, Login, Pass End Sub

This method creates a SOAP message to initiate a load task of an AccountingTrade object, which is then sent to the web service of the specified region by the 'ContinueLoad' method:

Sub ContinueLoad(data As String, url As String, Login As String, Pass As String) Dim StrXML As String Dim DirPathToXML As String Dim xmlHtp As Object Set xmlHtp = CreateObject("Microsoft.XmlHttp") Dim xDoc As MSXML2.DOMDocument Set xDoc = New MSXML2.DOMDocument DirPathToXML = CurDir() & "\tsr.xml" With xmlHtp .Open "POST", url & "/EagleMLWebService20", False, Login, Pass .setRequestHeader "Content-Type", "text/xml; charset=utf-8" .setRequestHeader "Host", Replace(Replace(url, "http://", ""), "https://", "") .setRequestHeader "Content-Encoding", "gzip, deflate" .setRequestHeader "soapAction", "/EagleMLWebService/LoadAccounting" .send "" & data xDoc.LoadXML .responseText End With Shell "cmd.exe /c cd. > " & DirPathToXML Open DirPathToXML For Output As #1 Print #1, xDoc.XML Reset ImportXMLToList DirPathToXML Set xmlHtp = Nothing Set xDoc = Nothing End Sub

This method sends a composed SOAP message to the web service and retrieves the TSR message, which is then imported to the table representation and is added to the TSR sheet of the workbook by the 'ImportXMLToList' method:

Sub ImportXMLtoList(PathToXML As String) Dim wb As Workbook Dim currentBook As Workbook Set currentBook = ActiveWorkbook Application.ScreenUpdating = False Application.DisplayAlerts = False Set wb = Workbooks.OpenXML(Filename:=PathToXML, LoadOption:=xlXmlLoadImportToList) Application.DisplayAlerts = True Dim tsrSheet As Object On Error Resume Next Set tsrSheet = currentBook.Sheets("TSR") If tsrSheet Is Nothing Then Set tsrSheet = currentBook.Sheets.Add(After:=currentBook.Sheets(currentBook.Sheets.Count)) tsrSheet.name = "TSR" Else tsrSheet.Cells.Clear End If wb.Sheets(1).UsedRange.Copy tsrSheet.Range("A1") wb.Close False tsrSheet.Activate With ActiveSheet.UsedRange ActiveSheet.Rows(.Rows.Count).Delete End With Application.ScreenUpdating = True End Sub