将XML文件附加到现有的Access表

时间:2018-06-27 22:03:03

标签: xml vba ms-access access-vba

我有一个XML文件,我需要将其导入到Access表中。 XML文件包含带有多个字段的Header,以及带有CDATA字段的报表主体,其中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数据和REPORT正文数据放入单独的表中。指定每个项目进入哪个字段的用于导入XML的VBA脚本是什么?这是我到目前为止所了解的:

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 :(得分:1)

我无法选择重组此XML ...实际上,您可以使用XSLT(一种用于转换XML文件的专用语言,MSXML运行XSLT 1.0脚本。

只需将 HEADER ReportBody 组合到一个节点中,例如 REPORT (将成为Access表的名称)。然后使用Access'Application.ImportXML导入此转换后的XML。

XSLT (另存为.xsl文件,一个特殊的.xml文件)

private bool dragging;

private string CurrentTool;

private ButtonController[] DrawingTools;

public Camera TheCamera;

public Vector3 MouseStart;
public Vector3 CameraStart;

public float sensitivity;

// Use this for initialization
void Start () {
    TheCamera = FindObjectOfType<Camera>();
    DrawingTools = FindObjectsOfType<ButtonController>();
}

// Update is called once per frame
void Update () {
    for (int i = 0; i < DrawingTools.Length; i++)
    {
        if (DrawingTools[i].Pressed)
        {
            CurrentTool = DrawingTools[i].gameObject.name;
        }
    }

    if (dragging && CurrentTool == "PanTool Button")
    {
        float xChange;
        float yChange;
        Vector3 MousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);

        if (MousePosition.x > MouseStart.x)
        {
            xChange = -Mathf.Abs(MousePosition.x - MouseStart.x);
        }
        else
        {
            xChange = Mathf.Abs(MousePosition.x - MouseStart.x);
        }

        if (MousePosition.y > MouseStart.y)
        {
            yChange = -Mathf.Abs(MousePosition.y - MouseStart.y);
        }
        else
        {
            yChange = Mathf.Abs(MousePosition.y - MouseStart.y);
        }

        TheCamera.transform.position = new Vector3(CameraStart.x + xChange*sensitivity, CameraStart.y + yChange*sensitivity, CameraStart.z);
    }
}

public void OnPointerDown(PointerEventData EventData)
{
    if (!dragging)
    {
        dragging = true;
        MouseStart = new Vector3(Camera.main.ScreenToWorldPoint(Input.mousePosition).x, Camera.main.ScreenToWorldPoint(Input.mousePosition).y, 0f);
        CameraStart = TheCamera.transform.position;
    }
}

public void OnPointerUp(PointerEventData EventData)
{
    if (dragging)
    {
        dragging = false;
    }
}

XSLT Fiddle Demo (请参见左下方的结果)

VBA (分离文件选择器的迭代和转换过程,假定所有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>

答案 1 :(得分:0)

虽然Zack有一个要点(如果您想让我们真正帮助您,您需要分享更多一点),但我可以尝试进一步帮助您。

首先,如果要在没有xsd的情况下解析该XML文档,则需要打开ValidateOnParse

然后,您可以使用以下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