提问人:LuPi1801 提问时间:9/12/2023 最后编辑:JohnMLuPi1801 更新时间:9/13/2023 访问量:54
如何将 DOMDocument 传递给子程序
How to pass DOMDocument to Subroutine
问:
我有一堆来自德国商业登记处的所谓“结构化数据”,这些数据以xml文件的形式出现(一个文件总是保存一家公司的数据)。数据结构符合德国“XJustiz”xml模式(一种专门为简化司法部门的电子数据交换而开发的方案)的规范。这个 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 都可以通过设置来显示 - 因此信息以某种方式在手边,但似乎带有标签和东西的 xml 结构丢失了(无论如何,它没有显示在我用来测试是否至少传递了任何数据的字符串中)。我真的不知道出了什么问题。strContent = xmlDoc.text
我真的很想避免将两个版本的(独立)工作代码放在一个模块中,因为每个版本都很长,结果将不再可维护。
一种解决方法是将每个工作代码在开始时使用单独的 for-each-loop 放在单独的模块中,并在一个版本的循环完成后触发另一个版本的下一个循环(这会导致不必要的循环,特别是如果将来会有更多不同的版本)。
答:
经过几天对这个问题的反复试验,我现在偶然发现,如果我声明 just 而不是使用 ,我可以将 DOM ByRef 传递给子例程,而无需对现有代码进行任何其他更改。我甚至不再需要对“Microsoft XML”的引用。因此,工作代码现在如下所示:Dim xmlDoc As Object
Set xmlDoc = New MSXML2.DomDocument60
Set xmlDoc = CreateObject("MSXML.DOMDocument")
Sub Read_XML_Data()
Dim xmlDoc As Object
Dim xmlNode As Object
Dim strFilePath As String
Dim strFolder As String
Dim strContent As String
'other code, doing stuff and assigning values to strFilePath and strFolder
[...]
Set xmlDoc = CreateObject("MSXML.DOMDocument")
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
strContent = Left(xmlNode.Attributes(0).Text, 1)
Select Case Left(xmlNode.Attributes(0).Text, 1)
Case 1
Read_XJustiz_v1 xmlDoc
Exit For
Case Else
MsgBox ("XJustiz Version: " & Left(xmlNode.Attributes(0).Text, 1))
Exit For
End Select
End If
Next
End Sub
Sub Read_XJustiz_v1(ByRef xmlDoc As Object)
'checking the entities legal form
If xmlDoc.getElementsByTagName("Beteiligter").Item(0).ChildNodes(1).ChildNodes(2).Text = "Gesellschaft mit beschränkter Haftung" Then 'no more error!
'do the rest of the code
[...]
End Sub
不幸的是,我无法解释为什么东西会像它一样工作,但它确实有效。
我希望如果有人遇到类似的问题,这可能会有所帮助
只是为了表明它可以正常工作:
Sub Read_XML_Data()
Dim xmlDoc As MSXML2.DOMDocument60, vers, rootName As String, nd As Object
Set xmlDoc = New MSXML2.DOMDocument60
xmlDoc.async = False
xmlDoc.SetProperty "SelectionLanguage", "XPath" 'to use XPath
'document has a "default namespace", so add that with a dummy alias `xx`...
xmlDoc.SetProperty "SelectionNamespaces", "xmlns:xx='http://www.xjustiz.de'"
xmlDoc.Load "C:\Temp\xjustiz.xml"
vers = xmlDoc.SelectSingleNode("//xx:nachrichtenkopf"). _
Attributes.getNamedItem("xjustizVersion").Text
Debug.Print vers '3.2.1
Select Case vers
Case "3.2.1"
Set nd = xmlDoc.SelectSingleNode("//xx:beteiligter")
Debug.Print "Read_XML_Data:", nd.ChildNodes(0).Text '.ChildNodes(0).Text
Read_XJustiz_v3_2_1 xmlDoc
Case Else
Debug.Print "Version:", vers
End Select
End Sub
Sub Read_XJustiz_v3_2_1(xmlDoc As DOMDocument60)
Dim nd As Object
Set nd = xmlDoc.SelectSingleNode("//xx:beteiligter")
Debug.Print "Read_XJustiz_v3_2_1:", nd.ChildNodes(0).Text '.ChildNodes(2).Text
End Sub
输出:
Read_XML_Data Muster und Kollegen 002
Read_XJustiz_v3_2_1 Muster und Kollegen 002
评论
Dim xmlDoc As MSXML2.DOMDocument60
Set xmlDoc = New MSXML2.DOMDocument60
Dim xmlDoc As Object
Set xmlDoc = CreateObject("MSXML.DOMDocument")
nd
只是一个泛型对象类型,用于分解原始代码中的一长串属性,以检查第一步是否找到匹配项。在将对象作为参数传递给其他方法时,早期绑定(第一个示例)和后期绑定(第二个示例)之间应该没有区别。有关早期与晚期绑定的更多信息:learn.microsoft.com/en-us/previous-versions/office/troubleshoot/...
评论
Read_XML_Data
Case 1