Добавить файл XML в существующую таблицу доступа - PullRequest
0 голосов
/ 28 июня 2018

У меня есть файл XML, который мне нужно импортировать в таблицу Access. Файл XML содержит заголовок с несколькими полями и тело отчета с полем CDATA, содержащим повторяющуюся информацию (текст с разделителями внутри CDATA). Вот основная версия того, как это выглядит:

<?xml version="1.0" encoding="UTF-8"?>
<CMCFReport      
xsi:noNameSpaceSchemaLocation="CMCReports.xsd"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <HEADER>
      <ModeS>A5A1ED</ModeS>
      <TailNumber>UNKNOWN</TailNumber>
      <Timestamp>
         <Day>1</Day>
         <Month>12</Month>
         <Year>2016</Year>
         <Hour>18</Hour>
         <Minute>36</Minute>
         <Second>58</Second>
       </Timestamp>
   </HEADER>
   <ReportBody>
      <StorageReport>
         <![CDATA[PLF 01DEC16 1835 --------- L
COL3A-0072-001N BCG3F-CMCM-002K
MSG 2158513 01DEC16 1714 TO           A 1  
FDE 21500944 01DEC16 1713 TA           A
FDE 21502445 01DEC16 1713 TA           A
MSG 2158512 01DEC16 1714 TO           A 1
EOR
]]>
    </StorageReport>
  </ReportBody>
</CMCFReport>

Когда я запускаю утилиту импорта, Access пытается поместить данные HEADER и данные тела отчета в отдельные таблицы. Что такое сценарий VBA для импорта XML, в котором вы указываете, в какое поле входит каждый элемент? Это насколько я дошел до сих пор:

Private Sub btn_Import_Click()
Dim StrFileName As String
   Dim fd As FileDialog
   Dim vrtSelectedItem As Variant
   Dim oDoc As MSXML2.DOMDocument60
   Set oDoc = New MSXML2.DOMDocument60
   Set fd = Application.FileDialog(msoFileDialogFilePicker)
   With fd.InitialFileName = "c:\sample\*.xml"
        If .Show = -1 Then
            For Each vrtSelectedItem In .SelectedItems
                If oDoc.Load(vrtSelectedItem) Then
                    Dim oNodes As MSXML2.IXMLDOMNodeList
                    oNodes = oDoc.Nodes

                    Dim oNode As MSXML2.IXMLDOMNode
                    For Each oNode In oNodes 
                    'This is where I imagine the code would be to pull the relevant data out of each node and assign it to a field, I just don't know how to do that`
                    Next oNode
                End If

            Next vrtSelectedItem
        Else
        End If
    End With
    Set fd = Nothing
End Sub

Я никогда раньше не импортировал XML, и у меня нет возможности реструктурировать этот XML, так как я буду получать файл из внешнего источника и импортировать его на регулярной основе. Любая помощь будет оценена. Спасибо.

Ответы [ 2 ]

0 голосов
/ 28 июня 2018

У меня нет возможности реструктурировать этот XML ... на самом деле вы делаете с XSLT , языком специального назначения, предназначенным для преобразования файлов XML и MSXML может запускать сценарии XSLT 1.0.

Просто объедините HEADER и ReportBody в один узел, такой как REPORT (который будет именем таблицы доступа). Затем импортируйте этот преобразованный XML с Access ' Application.ImportXML .

XSLT (сохранить как файл .xsl, специальный файл .xml)

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:noNameSpaceSchemaLocation="CMCReports.xsd" 
                version="1.0">
  <xsl:output method="xml" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="/*">
    <data>
      <xsl:apply-templates select="HEADER"/>
    </data>
  </xsl:template>

    <xsl:template match="HEADER|ReportBody">
        <REPORT>
            <xsl:copy-of select="ModeS|TailNumber"/>
            <xsl:copy-of select="Timestamp/*"/>
            <xsl:copy-of select="following-sibling::ReportBody/*"/>
        </REPORT>
    </xsl:template>

</xsl:stylesheet>

XSLT Fiddle Demo (см. Результат в левом нижнем углу)

VBA (разделяет итерацию средства выбора файлов и процесс преобразования, предполагается, что все XML-файлы имеют одинаковую структуру)

Private Sub btn_Import_Click()
On Error GoTo ErrHandle
    Dim StrFileName As String
    Dim fd As FileDialog
    Dim vrtSelectedItem As Variant

    ' ITERATE THROUGH MULTIPLE FILE PICKER
    Set fd = Application.FileDialog(msoFileDialogFilePicker)
    With fd.InitialFileName = "c:\sample\*.xml"
        If .Show = -1 Then
            For Each vrtSelectedItem In .SelectedItems
                ' TRANSFORM XML FILE
                StrFileName = CombineNodesXML(vrtSelectedItem)

                ' IMPORT TRANSFORMED XML (APPENDING TO EXISTING)                     
                Application.ImportXML StrFileName, acAppendData    
            Next vrtSelectedItem
        End If
    End With

ExitHandle:
    Set fd = Nothing
    Exit Sub

ErrHandle:
    Msgbox Err.Number & " - " & Err.Description, "RUNTIME ERROR", vbCritical
    Resume ExitHandle
End Sub

Public Function CombineNodesXML(xmlfile As Variant) As String
On Error GoTo ErrHandle
    Dim xmldoc As New MSXML2.DOMDocument, xslDoc As New MSXML2.DOMDocument, newDoc As New MSXML2.DOMDocument
    Dim outputfile As String         

    outputfile = Replace(xmlfile, ".xml", "_transformed.xml")

    ' LOAD XML AND XSL FILES
    xmlDoc.async = False
    xmlDoc.Load xmlfile

    xslDoc.async = False    
    xslDoc.Load "C:\Path\To\XSLT_Script.xml"        ' REPLACE WITH ABOVE XSLT PATH     

    ' TRANSFORM AND SAVE XML 
    xmldoc.transformNodeToObject xslDoc, newDoc
    newDoc.Save outputfile

    ' RETURN OUTPUT PATH
    CombineNodesXML = outputfile

ExitHandle:
    ' RELEASE OBJECTS
    Set xmlDoc = Nothing: Set xslDoc = Nothing: Set newDoc = Nothing
    Exit Function

ErrHandle:
    Msgbox Err.Number & " - " & Err.Description, "RUNTIME ERROR", vbCritical
    Resume ExitHandle
End Sub
0 голосов
/ 28 июня 2018

Хотя у Зака ​​есть смысл (вам нужно поделиться немного больше, если вы хотите, чтобы мы действительно помогли вам), я могу попытаться помочь вам в дальнейшем.

Во-первых, вам нужно включить ValidateOnParse, если вы собираетесь анализировать этот XML-документ без xsd.

Затем можно выполнить итерацию по всем текстовым узлам, содержащим фактический текст, используя следующий запрос XPATH:

//*[string-length(normalize-space(text())) > 0]/text()

Вам все равно придется заполнить сведения о том, как вы собираетесь хранить это, но это должно помочь вам начать. Он дает вам имя узла и значение для каждого узла, содержащего текст.

Вам все еще нужно добавить логику для их хранения в соответствующих полях вашей таблицы.

Public Sub btn_Import_Click()
   Dim StrFileName As String
   Dim fd As FileDialog
   Dim vrtSelectedItem As Variant
   Dim oDoc As MSXML2.DOMDocument60
   Set oDoc = New MSXML2.DOMDocument60
   oDoc.async = False
   oDoc.validateOnParse = True
   Set fd = Application.FileDialog(msoFileDialogFilePicker)
   With fd
        .InitialFileName = "c:\sample\*.xml"
        If .Show = -1 Then
            For Each vrtSelectedItem In .selectedItems
                If oDoc.Load(vrtSelectedItem) Then
                    Dim textNodes As IXMLDOMNodeList
                    Set textNodes = oDoc.SelectNodes("//*[string-length(normalize-space(text())) > 0]/text()")
                    Dim l As Long
                    For l = 0 To textNodes.length - 1
                        Debug.Print textNodes(l).ParentNode.nodeName 'Node name
                        Debug.Print textNodes(l).NodeValue 'Node value
                    Next
                End If

            Next vrtSelectedItem
        Else
        End If
    End With
    Set fd = Nothing
End Sub
...