简体   繁体   中英

Import XML data into MS Access table Using SQL and VB6

I have an XML file with many records down under "/response/result/record". For example:

<response>
  <result>
    <record>
      <flda>some text</flda>
      <fldb>some text</fldb>
      :     :     :
    </record>
    :    :    :
  </result>
</response>

I have an MSAccess database and a legacy VB6 program that needs to read this file and load it into a table containing a field for each text node in each record.

I know I can use MSXML2.DOMDocument to Load the XML from the internet and possibly save it to a file. I can also then use the DOMDocument to read the XML and load the MSAccess database table one record at a time.

This seems inefficient, since I can load CSV files into an MSAccess table using VB6 syntax such as:

db.Execute "Select * Into CSVtable From [Text;FMT=CSVDelimited;HDR=YES;DATABASE=dirPath].[filename]"

And it will quickly bulk load that data into the database. Much, much faster than reading each record from the CSV file and using a DAO recordset to add each record one at a time.

My question : can I do the same thing with an XML file? What is the syntax and how do I do it?

Follow-up question : Where do I find documentation on this funky 'Select...' syntax that I show above for CSV files (that I originally found on StackOverflow)?

The SELECT syntax that you want is defined only in the JETSQL40.CHM document as far as I can determine. This is normally installed with MS Office 2000 or later, but you'll have to dig around in the "Program Files" special folder to find it. There is enough useful stuff there that I usually create a shortcut to it myself.

However since there is no Jet XML Installable ISAM (IISAM) you would have to do the sort of thing that MS Access does itself to import XML format data.

While that does involve looping, you can do your bulk insert in a more optimal manner than people commonly do. The code used below attempts to do that.

This program has a Form with a single Menu item mnuImportXML and an MSHFlexGrid named FlexGrid to display the contents of a "Records" table in the database it creates on first run:

Option Explicit

Private Const CONNWG As String = "Provider=Microsoft.Jet.OLEDB.4.0;" _
                               & "Jet OLEDB:Engine Type=5;" _
                               & "Jet OLEDB:Create System Database=True;" _
                               & "Data Source='$DB$.mdw';"
Private Const CONNDB As String = "Provider=Microsoft.Jet.OLEDB.4.0;" _
                               & "Jet OLEDB:Engine Type=5;" _
                               & "Jet OLEDB:System Database='$DB$.mdw';" _
                               & "Data Source='$DB$.mdb';"

Private CN As ADODB.Connection
Private QueryRS As ADODB.Recordset
Private UpdateRS As ADODB.Recordset
Private XmlRS As ADODB.Recordset
Private recordsRS As ADODB.Recordset
Private AppendFields As Variant

Public Function OpenConnection(ByVal DbPath As String) As ADODB.Connection
    Dim ExtensionPos As Long

    ExtensionPos = InStrRev(DbPath, ".")
    If ExtensionPos > 0 Then DbPath = Left$(DbPath, ExtensionPos - 1)
    On Error Resume Next
    GetAttr DbPath & ".mdb"
    If Err Then
        On Error GoTo 0
        Set OpenConnection = CreateDB(DbPath)
    Else
        On Error GoTo 0
        Set OpenConnection = New ADODB.Connection
        OpenConnection.Open Replace$(CONNDB, "$DB$", DbPath)
    End If
End Function

Private Function CreateDB(ByVal DbPath As String) As ADODB.Connection
    Dim catDB As Object 'Don't early-bind ADOX objects.

    Set catDB = CreateObject("ADOX.Catalog")
    With catDB
        .Create Replace$(CONNWG, "$DB$", DbPath)
        .Create Replace$(CONNDB, "$DB$", DbPath)
        Set CreateDB = .ActiveConnection
        Set catDB = Nothing
    End With
    With CreateDB
        .Execute "CREATE TABLE [Records](" _
               & "[ID] IDENTITY CONSTRAINT PK_UID PRIMARY KEY," _
               & "[flda] TEXT(255) WITH COMPRESSION," _
               & "[fldb] TEXT(255) WITH COMPRESSION)", , _
                 adCmdText Or adExecuteNoRecords
    End With
End Function

Private Sub RefreshGrid()
    QueryRS.Open "[Records]", , , adLockReadOnly, adCmdTable
    Set FlexGrid.DataSource = QueryRS
    QueryRS.Close
End Sub

Private Sub Form_Load()
    Set CN = OpenConnection("demo.mdb")
    Set QueryRS = New ADODB.Recordset
    QueryRS.CursorLocation = adUseClient
    Set QueryRS.ActiveConnection = CN
    Set XmlRS = New ADODB.Recordset
    XmlRS.ActiveConnection = "Provider=MSDAOSP;Data Source=MSXML2.DSOControl.3.0"
    Set UpdateRS = New ADODB.Recordset
    Set UpdateRS.ActiveConnection = CN
    UpdateRS.Properties("Append-Only Rowset").Value = True
    AppendFields = Array("flda", "fldb")
    RefreshGrid
End Sub

Private Sub Form_Resize()
    If WindowState <> vbMinimized Then
        FlexGrid.Move 0, 0, ScaleWidth, ScaleHeight
    End If
End Sub

Private Sub Form_Unload(Cancel As Integer)
    CN.Close
End Sub

Private Sub mnuImportXML_Click()
    XmlRS.Open "response.xml"
    Set recordsRS = XmlRS.Fields("record").Value
    UpdateRS.Open "Records", , , adLockOptimistic, adCmdTableDirect
    CN.BeginTrans
    With recordsRS
        Do Until .EOF
            UpdateRS.AddNew AppendFields, _
                            Array(.Fields(AppendFields(0)).Value, _
                                  .Fields(AppendFields(1)).Value)
            .MoveNext
        Loop
    End With
    CN.CommitTrans
    UpdateRS.Close
    Set recordsRS = Nothing
    XmlRS.Close
    RefreshGrid
End Sub

The key here is the Menu event handler mnuImportXML_Click (scroll down to the end) which appends the Text of the flda and fldb sub-elements of the repeated second-level XML element record into the Jet database table Records .

Note the use of:

UpdateRS.Properties("Append-Only Rowset").Value = True

That is done during initialization within Form_Load. It improves performance a bit.

I'm not aware of any quicker way to accomplish this. Jet can't use an XML document as an external database. It can only make use of database types that it has an IISAM for such as Text, HTML, Excel 8.0, dBase IV, and Paradox.

Whether Microsoft was just lazy and left XML out of Jet 4.0 without thinking, the hierarchical nature of XML documents didn't leave them many options without extending Jet SQL syntax, or there is some syntax I haven't found... I just can't say.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM