To load a bill of materials into SAP I needed to create a XML file with the hierarchy of the bill. To start this project in Access you will need to set a reference to ChilkatXML  (free from chilkatsoft.com), or you use MS DOM Object but I prefer the coding structure provided by chilkat,   and a table for the BOM items. Starting with the top levels you can then create the required number of BOM levels. You will need to amend the nodes of the XML file to suit your BOM levels.

Sub Make_SAP_XML_v3()
'------------------------------------------------------
' 'Excel macro to Export a BOM for SAP Upload
'-----------------------------------------------------
Dim xml As New ChilkatXml
Dim BookingHeader As ChilkatXml
Dim ProductHeader As ChilkatXml
Dim Systems As ChilkatXml
Dim System As ChilkatXml

Dim tmpTest As Boolean, myFile, tmpStr, tmpFile, tmpPath, tmpRev, tmpCount
Dim tmpCabinet As String, tmpCurr As String
Dim tmpVal As String, tmpSystemID As String
Dim tmpName As String
Dim tmpCabType As String
Dim tmpProType As String
Dim I As Integer
Dim tmpSystem As String
Dim tmpTopLevel As Integer
Dim tmpATO As Integer
Dim tmpSystemLine As Integer

Dim tmpOrder
Dim tmpItemNo As Integer, tmpOrderLine As Integer, tmpItemNo2 As Integer
Dim tmptestPO As Boolean, tmpBOMDesc, tmpCost

Dim x As Variant
Dim ws As Worksheet
Set ws = Worksheets("Descriptions")

xml.Tag = "MT_Project_WBSBOM_CREATE"
xml.AddAttribute "xmlns:nr1", "http://xxxxxx.com/contract_to_order"

ActiveWorkbook.Worksheets("Header").Select

Range("f1").Select
If ActiveCell.Value > 0 Then
    MsgBox "You are missing manditory information on the Header tab" & vbCrLf & "Please correct the data and retry"
    Exit Sub
End If

Range("c2").Select

Set BookingHeader = xml.NewChild("BookingHeader", "")

BookingHeader.NewChild2 "SoldtoCompany", ActiveCell.Offset(1, 0).Value
BookingHeader.NewChild2 "SoldtoAddress1", ActiveCell.Offset(2, 0).Value
BookingHeader.NewChild2 "SoldtoAddress2", ActiveCell.Offset(3, 0).Value
BookingHeader.NewChild2 "SoldtoAddress3", ActiveCell.Offset(4, 0).Value
BookingHeader.NewChild2 "SoldtoAddress4", ActiveCell.Offset(5, 0).Value
BookingHeader.NewChild2 "SoldtoAttn", ActiveCell.Offset(6, 0).Value
BookingHeader.NewChild2 "HardwareShiptoCompany", ActiveCell.Offset(8, 0).Value
BookingHeader.NewChild2 "HardwareShiptoAddress1", ActiveCell.Offset(9, 0).Value
BookingHeader.NewChild2 "HardwareShiptoAddress2", ActiveCell.Offset(10, 0).Value
BookingHeader.NewChild2 "HardwareShiptoAddress3", ActiveCell.Offset(11, 0).Value
BookingHeader.NewChild2 "HardwareShiptoAddress4", ActiveCell.Offset(12, 0).Value
BookingHeader.NewChild2 "DeliveryContact", ActiveCell.Offset(14, 0).Value
BookingHeader.NewChild2 "DeliveryPhone", ActiveCell.Offset(15, 0).Value
BookingHeader.NewChild2 "SalesOrder", ActiveCell.Offset(17, 0).Value
BookingHeader.NewChild2 "OracleCIBSoldtoPartnerNumber", ActiveCell.Offset(19, 0).Value
BookingHeader.NewChild2 "OracleDefaultTaskCode", ActiveCell.Offset(20, 0).Value
BookingHeader.NewChild2 "OracleID", ActiveCell.Offset(21, 0).Value
BookingHeader.NewChild2 "PurchaseOrderNumber", ActiveCell.Offset(23, 0).Value
BookingHeader.NewChild2 "ProjectName", ActiveCell.Offset(24, 0).Value
BookingHeader.NewChild2 "OrderType", ActiveCell.Offset(26, 0).Value
BookingHeader.NewChild2 "EndUserCompany", ActiveCell.Offset(28, 0).Value
BookingHeader.NewChild2 "EndUserAddress1", ActiveCell.Offset(29, 0).Value
BookingHeader.NewChild2 "EndUserAddress2", ActiveCell.Offset(30, 0).Value
BookingHeader.NewChild2 "EndUserAddress3", ActiveCell.Offset(31, 0).Value
BookingHeader.NewChild2 "EndUserCity", ActiveCell.Offset(32, 0).Value
BookingHeader.NewChild2 "EndUserState", ActiveCell.Offset(33, 0).Value
BookingHeader.NewChild2 "EndUserCountry", ActiveCell.Offset(34, 0).Value
BookingHeader.NewChild2 "EndUserContactTelephone", ActiveCell.Offset(35, 0).Value
BookingHeader.NewChild2 "EndUserPostalCode", ActiveCell.Offset(36, 0).Value
BookingHeader.NewChild2 "RequestDate", ActiveCell.Offset(38, 0).Value
BookingHeader.NewChild2 "TradeTerms", ActiveCell.Offset(40, 0).Value
BookingHeader.NewChild2 "FreightForwarderName", ActiveCell.Offset(42, 0).Value
BookingHeader.NewChild2 "FreightForwarderAddress1", ActiveCell.Offset(43, 0).Value
BookingHeader.NewChild2 "FreightForwarderAddress2", ActiveCell.Offset(44, 0).Value
BookingHeader.NewChild2 "FreightForwarderCity", ActiveCell.Offset(45, 0).Value
BookingHeader.NewChild2 "FreightForwarderState", ActiveCell.Offset(46, 0).Value
BookingHeader.NewChild2 "FreightForwarderCountry", ActiveCell.Offset(47, 0).Value
BookingHeader.NewChild2 "FreightForwarderTelephone", ActiveCell.Offset(48, 0).Value
BookingHeader.NewChild2 "FreightForwarderPostalCode", ActiveCell.Offset(49, 0).Value
BookingHeader.NewChild2 "FreightTerms", ActiveCell.Offset(50, 0).Value
BookingHeader.NewChild2 "ShippingMarks1", ActiveCell.Offset(52, 0).Value
BookingHeader.NewChild2 "ShippingMarks2", ActiveCell.Offset(53, 0).Value
BookingHeader.NewChild2 "ShippingMarks3", ActiveCell.Offset(54, 0).Value
BookingHeader.NewChild2 "ShippingMarks4", ActiveCell.Offset(55, 0).Value
tmpCurr = ActiveCell.Offset(57, 0).Value
tmpBOMDesc = ActiveCell.Offset(59, 0).Value



'set the header values
Set ProductHeader = xml.NewChild("WBSBOMHeader", "")

ActiveWorkbook.Worksheets("Version").Select
Range("B1").Select

ProductHeader.NewChild2 "ConfigSource", ActiveCell.Value
ProductHeader.NewChild2 "TPCVersion", ActiveCell.Offset(1, 0).Value
ProductHeader.NewChild2 "TPCInternalDate", ActiveCell.Offset(2, 0).Value
ProductHeader.NewChild2 "TPCEngInfoDate", ActiveCell.Offset(3, 0).Value
ProductHeader.NewChild2 "TPCEngInfoFileVersion", ActiveCell.Offset(4, 0).Value
ProductHeader.NewChild2 "CommerciallyComplete", ActiveCell.Offset(5, 0).Value


ProductHeader.NewChild2 "WBSBOMCurrencyCode", tmpCurr
ProductHeader.NewChild2 "OpportunityID", ""     'rst!ID 'use the is of the passed recordset
ProductHeader.NewChild2 "QuoteID", ""
ProductHeader.NewChild2 "GlobalProjectID", ""


ActiveWorkbook.Worksheets("Factory_BOM").Select
Range("A1").Select

If Range("A1") <> "System" Then
    MsgBox ("This is not the correct sheet")
    Exit Sub
End If


ProductHeader.NewChild2 "SystemID", tmpBOMDesc

tmpSystemLine = 0
tmpSystem = ""
tmpOrderLine = 1

tmpItemNo = 1
tmpSystemLine = tmpSystemLine + 1
tmpItemNo = 0
tmpItemNo2 = 1
tmpTopLevel = 1
tmpATO = 0
    
tmpTest = True
tmpStr = ""
Application.ScreenUpdating = False

Range("A1").Select

If Range("A1") <> "System" Then
    MsgBox ("This is not the correct sheet")
    Exit Sub
End If


If Len(Range("C1") & "") < 4 Then
    MsgBox ("Please Enter 'Rev X' in B1")
    Exit Sub
End If

Range("A2").Select
tmpSystem = ActiveCell.Value
tmpCabinet = ""


Set Systems = ProductHeader.NewChild("WBSBOMItem", "")
'Make a new Parent
'_____________________________________
Systems.NewChild2 "WBSBOMParentName", ""
Systems.NewChild2 "WBSBOMProduct", tmpSystem
Systems.NewChild2 "WBSBOMLineNumber", tmpOrderLine
Systems.NewChild2 "WBSBOMQuantity", "1"
Systems.NewChild2 "WBSBOMRowID", tmpOrderLine 'tmpPro & "_" & tmpOrderLine 'TmpProType & "0" & tmpOrderLine & "_" & tmpOrderLine
Systems.NewChild2 "WBSBOMCustomerSupplied", ""
'lookup the cabinet description
On Error GoTo Skip
x = Application.WorksheetFunction.VLookup(tmpSystem, ws.Range("A5:B105"), 2, False)
Skip:
Systems.NewChild2 "WBSBOMDescription", IIf(x <> 0, x, "")
Systems.NewChild2 "WBSBOMImportSource", ""
Systems.NewChild2 "WBSBOMMilestoneBillFlag", ""
Systems.NewChild2 "WBSBOMParentItemNumber", "0"
Systems.NewChild2 "WBSBOMType", ""
Systems.NewChild2 "WBSBOMUnitCost", ""
Systems.NewChild2 "WBSBOMUnitOfMeasure", tmpCurr
Systems.NewChild2 "WBSBOMName", ""
Systems.NewChild2 "WBSBOMPackage", ""
Systems.NewChild2 "WBSBOMPkgDescription", ""
'________________________________________

tmpCount = 2

Do While tmpTest
    
    ActiveCell.Offset(0, 1).Select
    If ActiveCell.Value <> "" Then
    
        If tmpSystem <> ActiveCell.Offset(0, -1) Then
            '-------------------------------------------------
            tmpTopLevel = tmpTopLevel + 1
            tmpATO = 0
            
            tmpSystem = ActiveCell.Offset(0, -1)
            Set Systems = ProductHeader.NewChild("WBSBOMItem", "")
            Systems.NewChild2 "WBSBOMParentName", ""
            Systems.NewChild2 "WBSBOMProduct", ActiveCell.Offset(0, -1)
            Systems.NewChild2 "WBSBOMLineNumber", tmpTopLevel  ' tmpOrderLine
            Systems.NewChild2 "WBSBOMQuantity", "1"
            Systems.NewChild2 "WBSBOMRowID", tmpTopLevel  'tmpSystemLine & "." & tmpItemNo 'tmpPro & "_" & tmpOrderLine 'TmpProType & "0" & tmpOrderLine & "_" & tmpOrderLine
            Systems.NewChild2 "WBSBOMCustomerSupplied", ""
            'lookup the cabinet description
            On Error GoTo Skip1
            x = Application.WorksheetFunction.VLookup(tmpSystem, ws.Range("A5:B105"), 2, False)
Skip1:
            Systems.NewChild2 "WBSBOMDescription", IIf(x <> 0, x, "")
            Systems.NewChild2 "WBSBOMImportSource", ""
            Systems.NewChild2 "WBSBOMMilestoneBillFlag", ""
            Systems.NewChild2 "WBSBOMParentItemNumber", "0"
            Systems.NewChild2 "WBSBOMType", ""
            Systems.NewChild2 "WBSBOMUnitCost", ""
            Systems.NewChild2 "WBSBOMUnitOfMeasure", tmpCurr
            Systems.NewChild2 "WBSBOMName", ""
            Systems.NewChild2 "WBSBOMPackage", ""
            Systems.NewChild2 "WBSBOMPkgDescription", ""
            '-------------------------------------------------
        End If
        
        'are we starting a new system node?
        If tmpCabinet <> ActiveCell.Value Then
        
            tmpCabinet = ActiveCell.Value
            tmpOrderLine = tmpOrderLine + 1
            tmpSystemLine = tmpOrderLine
            tmpATO = tmpATO + 1
            tmpItemNo = 0
            
            
            'check contents
            '-------------------------------------------------
            Set Systems = ProductHeader.NewChild("WBSBOMItem", "")
            Systems.NewChild2 "WBSBOMParentName", ""
            Systems.NewChild2 "WBSBOMProduct", tmpCabinet
            Systems.NewChild2 "WBSBOMLineNumber", tmpTopLevel & "." & tmpATO
            Systems.NewChild2 "WBSBOMQuantity", "1"
            Systems.NewChild2 "WBSBOMRowID", tmpTopLevel & "." & tmpATO
            Systems.NewChild2 "WBSBOMCustomerSupplied", ""
            'lookup the cabinet description
            On Error GoTo Skip2
            x = Application.WorksheetFunction.VLookup(tmpCabinet, ws.Range("C5:D105"), 2, False)
Skip2:
            Systems.NewChild2 "WBSBOMDescription", IIf(x <> 0, x, "")
            Systems.NewChild2 "WBSBOMImportSource", ""
            Systems.NewChild2 "WBSBOMMilestoneBillFlag", ""
            Systems.NewChild2 "WBSBOMParentItemNumber", tmpTopLevel
            Systems.NewChild2 "WBSBOMType", ""
            Systems.NewChild2 "WBSBOMUnitCost", ""
            Systems.NewChild2 "WBSBOMUnitOfMeasure", tmpCurr
            Systems.NewChild2 "WBSBOMName", ""
            Systems.NewChild2 "WBSBOMPackage", ""
            Systems.NewChild2 "WBSBOMPkgDescription", ""
            
            tmpSystem = ActiveCell.Offset(0, -1)
            '-------------------------------------------------
            ActiveCell.Offset(0, 0).Select
            
        End If
        
        
        
        ActiveCell.Offset(0, 4).Select
        
        If ActiveCell.Value <> 0 Then
        
            ActiveCell.Offset(0, -4).Select
            Set Systems = ProductHeader.NewChild("WBSBOMItem", "")
            tmpItemNo = tmpItemNo + 1
            ActiveCell.Offset(0, 2).Select
            Systems.NewChild2 "WBSBOMParentName", "" ' tmpPro & "_" & tmpSystemLine 'o 'TmpProType & "0" & tmpOrderLine
            Systems.NewChild2 "WBSBOMProduct", UCase(ActiveCell.Value) 'rst![Lot_code_Sap] 'rst!Product
            Systems.NewChild2 "WBSBOMLineNumber", tmpTopLevel & "." & tmpATO & "." & tmpItemNo
            ActiveCell.Offset(0, 2).Select
            Systems.NewChild2 "WBSBOMQuantity", ActiveCell.Value '1 'rst!Qty
            Systems.NewChild2 "WBSBOMRowID", tmpTopLevel & "." & tmpATO & "." & tmpItemNo 'tmpSystemLine & "." & tmpItemNo 'tmpPro & "_" & tmpSystemLine & "." & tmpItemNo 'TmpProType & "0" & tmpOrderLine & "_" & tmpSystemLine & "." & tmpItemNo
            Systems.NewChild2 "WBSBOMCustomerSupplied", ""
            'gather cost for line
            tmpCost = 0
            ActiveCell.Offset(0, 1).Select
            tmpCost = ActiveCell.Value
            ActiveCell.Offset(0, 1).Select
            Systems.NewChild2 "WBSBOMDescription", ActiveCell.Value
            Systems.NewChild2 "WBSBOMImportSource", ""
            Systems.NewChild2 "WBSBOMMilestoneBillFlag", ""
            Systems.NewChild2 "WBSBOMParentItemNumber", tmpTopLevel & "." & tmpATO
            Systems.NewChild2 "WBSBOMType", ""
            Systems.NewChild2 "WBSBOMUnitCost", tmpCost
            Systems.NewChild2 "WBSBOMUnitOfMeasure", tmpCurr
            Systems.NewChild2 "WBSBOMName", ""
            Systems.NewChild2 "WBSBOMPackage", ""
            Systems.NewChild2 "WBSBOMPkgDescription", ""
            ActiveCell.Offset(1, -7).Select
        Else
            ActiveCell.Offset(1, -5).Select
        End If
        tmpStr = ""
    Else
        tmpTest = False
    End If
Loop

Application.ScreenUpdating = True
Range("A1").Select
        
tmpItemNo2 = tmpItemNo2 + 1

tmpName = ActiveWorkbook.Name
tmpName = Left(tmpName, (Len(tmpName) - 4))

'  Save the XML:
Dim success As Long
success = xml.SaveXml("c:\SAPXML\V6_" & tmpName & ".xml")
If (success <> 1) Then
    MsgBox xml.LastErrorText
End If

MsgBox ("c:\SAPXML\V6_" & tmpName & ".xml Created")

Exit_Func:
Set ProductHeader = Nothing
Set Systems = Nothing
Set System = Nothing




End Sub

Hi, I’m Pat