如何在 XML selectNodes 和 selectSingleNode 中使用命名空间

问题描述 投票:0回答:1

我正在将 VBA Access 应用程序从 Win7 移植到 Win11,我认为应该有一种方法可以做得更优雅。我必须阅读这个 .xml 文件:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
   <Document 
 xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:camt.053.001.08 camt.053.001.08.xsd"
 xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.08"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <BkToCstmrStmt>
            <GrpHdr>
                <MsgId>MSG-C053-231229020607-01</MsgId>
                <CreDtTm>2023-12-29T14:06:07.386+01:00</CreDtTm>
                <AddtlInf>RECONSTRUCTION</AddtlInf>
            </GrpHdr>
            <Stmt>
                <Id>STM-C053-231229020607-01</Id>
                <ElctrncSeqNb>999999</ElctrncSeqNb>
                <CreDtTm>2023-12-29T14:06:07.386+01:00</CreDtTm>
                <FrToDt>
                    <FrDtTm>2023-11-29T00:00:00.000+01:00</FrDtTm>
                    <ToDtTm>2023-12-28T23:59:59.999+01:00</ToDtTm>
                </FrToDt>
                <CpyDplctInd>DUPL</CpyDplctInd>
                <Acct>
                    <Id>
                        <IBAN>CHxxxxxxxxxxxxxxxxx</IBAN>
                    </Id>
                    <Ccy>CHF</Ccy>
                    <Ownr>
                        <Nm>Entity</Nm>
                    </Ownr>
                    <Svcr>
                        <FinInstnId>
                            <Nm>Name of Bank</Nm>
                        </FinInstnId>
                    </Svcr>
                </Acct>
                <Bal>
            <Shortened> 
            </Shortened>
                 </Bal>
                <Bal>
            <Shortened> 
            </Shortened>
                </Bal>
                <Ntry>
            <Shortened> 
            </Shortened>
                </Ntry>
    
            </Stmt>
        </BkToCstmrStmt>
</Document>

在Win7中使用\Windows\system32\msxml6.dll,这段代码做得很完美:

Sub ReadCamt053(strDPFE As String)
    
    Dim bankDownload As MSXML2.DOMDocument
      Set bankDownload = New MSXML2.DOMDocument
      bankDownload.validateOnParse = True
      bankDownload.Load strDPFE
      
      Dim groupHeader As IXMLDOMNode
      For Each groupHeader In bankDownload.selectNodes("Document/BkToCstmrStmt/GrpHdr")
        Debug.Print "Erzeugungsdatum(CreDtTm)", groupHeader.selectSingleNode("CreDtTm").Text
      Next groupHeader
      
      Dim accountStatement As IXMLDOMNode
      For Each accountStatement In bankDownload.selectNodes("Document/BkToCstmrStmt/Stmt")
        gIBAN = accountStatement.selectSingleNode("Acct/Id/IBAN").Text
        gSequenzNr = accountStatement.selectSingleNode("ElctrncSeqNb").Text
        ReadStatementEntries accountStatement.selectNodes("Ntry")
      Next accountStatement
End Sub

对于Win11 \Windows\SysWOW64\msxml6.dll 的移植,选择了XML,这需要使用DOMDocument60 而不是DOMDocument。使用 Google,我从 MS 找到了 this,并假设我必须添加一个命名空间才能读取 XML。我这样做了,但我无法找到一种优雅的方式来添加 groupHeader.selectSingleNode("CreDtTm").Text 的名称空间 - groupHeader.selectSingleNode("/ns:CreDtTm").Text 导致错误 91,使用

groupHeader.selectSingleNode("/bk:Document/bk:BkToCstmrStmt/bk:GrpHdr/bk:CreDtTm").Text
有效,但似乎很难阅读......

Sub ReadCamt053(strDPFE As String)
    
    Dim bankDownload As MSXML2.DOMDocument60
      Set bankDownload = New MSXML2.DOMDocument60
      bankDownload.validateOnParse = True
      bankDownload.SetProperty "SelectionNamespaces", "xmlns:ns='urn:iso:std:iso:20022:tech:xsd:camt.053.001.08'"
      bankDownload.Load strDPFE
      
      Dim groupHeader As IXMLDOMNode
      For Each groupHeader In bankDownload.selectNodes("/ns:Document/ns:BkToCstmrStmt/ns:GrpHdr")    
        Debug.Print "Erzeugungsdatum(CreDtTm)", groupHeader.selectSingleNode("CreDtTm").Text     '<---
      Next groupHeader
      
      Dim accountStatement As IXMLDOMNode
      For Each accountStatement In bankDownload.selectNodes("Document/BkToCstmrStmt/Stmt")
        gIBAN = accountStatement.selectSingleNode("Acct/Id/IBAN").Text
        gSequenzNr = accountStatement.selectSingleNode("ElctrncSeqNb").Text
        ReadStatementEntries accountStatement.selectNodes("Ntry")
      Next accountStatement
End Sub

我对 .XML 的了解非常有限(尝试错误)。所以这是我的两个问题:

  1. 有没有比 groupHeader.selectSingleNode("/bk:Document/bk:BkToCstmrStmt/bk:GrpHdr/bk:CreDtTm") 更好的方法

  2. 有关这个名称空间的整个内容看起来相当笨拙。有没有办法在不不断重复名称空间的情况下做到这一点 - 我确实只有这个单一的名称空间,所以这似乎是一个巨大的杀伤力......旧的东西完成了工作,看起来好多了......

xml vba namespaces xml-namespaces ms-access-2016
1个回答
0
投票

1- 如果添加命名空间,则修改代码如下:

For Each groupHeader In bankDownload.selectNodes("ns:Document/ns:BkToCstmrStmt/ns:GrpHdr")
    Debug.Print "Erzeugungsdatum(CreDtTm)", groupHeader.selectSingleNode("ns:CreDtTm").Text
Next groupHeader
      
For Each accountStatement In bankDownload.selectNodes("ns:Document/ns:BkToCstmrStmt/ns:Stmt")
    gIBAN = accountStatement.selectSingleNode("ns:Acct/ns:Id/ns:IBAN").Text
    gSequenzNr = accountStatement.selectSingleNode("ns:ElctrncSeqNb").Text
    ReadStatementEntries accountStatement.selectNodes("ns:Ntry")
Next accountStatement

2- 从文档中删除命名空间,使

<Document  xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:camt.053.001.08 camt.053.001.08.xsd" xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.08" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
变为
<Document>
并像以前一样使用原始代码:

Const s1 = "xsi:schemaLocation=""urn:iso:std:iso:20022:tech:xsd:camt.053.001.08 camt.053.001.08.xsd"""
Const s2 = "xmlns=""urn:iso:std:iso:20022:tech:xsd:camt.053.001.08"""
Const s3 = "xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"""

Dim bankDownload As New MSXML2.DOMDocument60
bankDownload.validateOnParse = False
bankDownload.Load Path_To_XML_File
Dim xml As String
xml = bankDownload.xml
xml = Replace(xml, s1, "")
xml = Replace(xml, s2, "")
xml = Replace(xml, s3, "")
bankDownload.loadXML xml

Dim groupHeader As IXMLDOMNode
For Each groupHeader In bankDownload.selectNodes("Document/BkToCstmrStmt/GrpHdr")
    Debug.Print "Erzeugungsdatum(CreDtTm)", groupHeader.selectSingleNode("CreDtTm").Text
Next groupHeader
      
Dim accountStatement As IXMLDOMNode
     
For Each accountStatement In bankDownload.selectNodes("Document/BkToCstmrStmt/Stmt")
    gIBAN = accountStatement.selectSingleNode("Acct/Id/IBAN").Text
    gSequenzNr = accountStatement.selectSingleNode("ElctrncSeqNb").Text
    ReadStatementEntries accountStatement.selectNodes("Ntry")
Next accountStatement
© www.soinside.com 2019 - 2024. All rights reserved.