我有一堆来自德国商业登记处的所谓“结构化数据”,它们以 xml 文件形式存在(一个文件始终保存一家公司的数据)。数据结构符合德国“XJustiz”xml-schema(专门为简化司法部门电子数据交换而开发的方案)的规范。该 xml 模式会定期更新,不幸的是它会不时更改结构或使用的 ID 和标记名。此外,从商业登记处收集的数据并不符合统一的 XJustiz 格式,目前数据有时以 XJustiz 版本 1 的结构提供,有时以 XJustiz 版本 3 的结构提供。
我已经有了工作代码,用于循环遍历桌面文件夹中所有下载的 xml 文件、读取 xml 结构并在工作簿中写下所需信息,以便进一步处理 XJustiz 版本 1 和 3 的法律分析在一个单独的文件中。
我现在想要实现的是通过首先应用一个过程来组合这两个代码,该过程检查某个节点,该节点保存有关所使用的 XJustiz 版本的信息,然后调用与该特定结构相对应的子例程。
我当前的代码如下所示,循环遍历指定目录,将每个 xml 文件设置为新的 DOMDocument60,读取包含版本信息的节点,然后执行子过程,将引用传递给 xmlDoc - 理论上是这样。这就是我请求您帮助的地方!在子例程中,尝试处理 DOM 的第一行始终会抛出运行时错误“91”:未设置对象变量或块变量。
第一个例程的当前代码:
Sub Read_XML_Data()
[...]
'########## MAIN LOOP START ##########
Do While Len(strFilePath) > 0
Set xmlDoc = New MSXML2.DOMDocument60
xmlDoc.async = False
xmlDoc.Load (strFolder & strFilePath)
'Checking the XJustiz version
For Each xmlNode In xmlDoc.getElementsByTagName("*")
If StrComp(xmlNode.Attributes(0).Name, "xjustizversion", vbTextCompare) = 0 Then
Select Case Left(xmlNode.Attributes(0).Text, 1)
'Found version 1 and execute corresponding subroutine
Case 1
Read_XJustiz_v1 xmlDoc
Exit For
Case Else
MsgBox (strFilePath & " verwendet XJustiz Version " & Left(xmlNode.Attributes(0).Text, 1))
Exit For
End Select
End If
Next
strFilePath = Dir
Loop
'########## MAIN LOOP END ##########
End Sub
子程序:
Sub Read_XJustiz_v1(ByRef xmlDoc As DOMDocument60)
Dim strContent As String
strContent = xmlDoc.Text
'This line raises the Error No. 91: Object Variable or With Block Variable Not Set.
If xmlDoc.getElementsByTagName("Beteiligter").Item(0).ChildNodes(1).ChildNodes(2).Text = "Gesellschaft mit beschränkter Haftung" Then
[...]
End If
End Sub
那么为什么我不能从子例程访问 DOM 以及需要更改什么才能使其正常工作?
我检查过,处理后的 xml 文件确实包含该项目
xmlDoc.getElementsByTagName("Beteiligter").Item(0).ChildNodes(1).ChildNodes(2).Text
所以我认为这不是这里的问题。
我已经尝试通过传递当前的 strFolder 和 strFile ByVal 来避免传递 DOM,从而从第二个子例程内部重新设置和重新加载 DOM。但是,一旦在第二个子例程中访问 DOM,这样做也会导致运行时错误“91”。
令人恼火的是,在这两种情况下,DOM(称为 xmlDoc)都可以通过设置
strContent = xmlDoc.text
来显示 - 所以信息以某种方式就在手边,但似乎带有标签和内容的 xml 结构丢失了(无论如何它都没有显示在我用来测试是否至少传递了任何数据的字符串)。我真的不知道出了什么问题。
我真的很想避免将两个版本的(独立)工作代码放在一个模块中,因为每个版本都很长,而且结果将不再可维护。
一种解决方法可能是将每个工作代码在单独的模块的开头放置一个单独的 for-each-循环,并在一个版本的循环完成后触发另一个版本的下一个循环(这会导致不必要的循环,特别是如果未来将会有更多不同的版本)。
经过几天的尝试和错误,这个问题我现在刚刚发现,即使我仍然没有设法将 DOM ByRef 传递给子例程,我可以“传递引用”给子例程通过使用上面代码中的 strFolder 和 strFilePath 仅不会引发错误号 91 如果我在第二个子例程中使用以下代码:
Sub Read_XJustiz_v1(ByVal strFilePath, strFolder As String)
Dim xmlDoc As Object
Set xmlDoc = CreateObject("MSXML.DOMDocument")
xmlDoc.async = False
xmlDoc.Load strFolder & strFilePath
'Rechtsformprüfung
If xmlDoc.getElementsByTagName("Beteiligter").Item(0).ChildNodes(1).ChildNodes(2).Text = "Gesellschaft mit beschränkter Haftung" Then '[no more error!]
我偶然发现了它,不幸的是,我无法解释为什么东西会这样工作,但只有当我声明
Dim xmlDoc As Object
而不是 Set xmlDoc = New MSXML2.DomDocument60
使用 Set xmlDoc = CreateObject("MSXML.DOMDocument")
时,它才有效
使用
Set xmlDoc = New MSXML.DOMDocument
(错误:用户定义类型)和 Set xmlDoc = New MSXML2.DOMDocument60
(尝试访问时出现错误 91)进行的试验确实没有结果。 xmlDoc.async = False
不是强制性的,但明显加快了进程。
我希望这对遇到类似问题的人有所帮助