Looking for help to port a function that returns an MSXML2.DOMDocument60 object from VBA to LO Basic

In VBA, I use the following function to simplify the process of reading an XML file into an MSXML2.DOMDocument60 object:

Public Function GetXMLFromFile2(strFilePath As String) As MSXML2.DOMDocument60

' ----------------------------------------------------------------
' Procedure Name: GetXML
' Purpose: Get XML from file into an MSXML2.DOMDocument60
' Procedure Kind: Function
' Procedure Access: Public
' Author: USER002
' Date: 06/12/2021
' ----------------------------------------------------------------

    ' Declarations

        Dim objDOMDoc As New MSXML2.DOMDocument60

    ' Set up error handler

        On Error GoTo ErrHandler

    ' Set up basic options for loading the XML file into objDOMDoc

        With objDOMDoc
            .async = False
            .validateOnParse = False
            .preserveWhiteSpace = True
        End With

    ' Load the XML from input.xliff into objDOMDoc

        objDOMDoc.Load (strFilePath)

        Set GetXMLFromFile = objDOMDoc

ExitHere:
    'On Error GoTo 0
    Exit Function

ErrHandler:
    Debug.Print Err.Number, Err.Description
    Select Case Err.Number
    Case 12345
        'Do something
    Case Else
    End Select

End Function

In LO Basic, I have tried to recreate this function as follows:

Function GetXMLFromFile(strFilePath As String) As Object

	'Declarations
		'Dim objDOMDoc As New MSXML2.DOMDocument60
		Dim objDOMDoc As Object
		Dim objOLEService As Object
		
		
	'Create UNO service	
		objOLEService = createUnoService("com.sun.star.bridge.OleObjectFactory") 
	
	' Create an XML object to export
    	objDOMDoc = objOLEService.createInstance("Msxml.DOMDocument")

	'Get the XML document
		objDOMDoc.Load("C:tmp\test1.xml")
		
	'Return the XML document
		GetXMLFromFile = objDOMDoc

End Function

I test the function like this:

Sub TestFunction

	'Declarations
		Dim objDOMDoc As Object
		Dim objOLEService As Object
		Dim oNode As Object
		
		
	'Create UNO service	
		objOLEService = createUnoService("com.sun.star.bridge.OleObjectFactory") 
	
	' Create an XML object to export
    	objDOMDoc = objOLEService.createInstance("Msxml.DOMDocument")
	
		objDOMDoc = GetXMLFromFile
		
		oNode = objDOMDoc.DocumentElement.getElementsByTagName("ElementA").Item(0)
		
	    MsgBox oNode.xml
	
End Sub

Regrettably this does not work, and I have no idea why. When it hits the line

oNode = objDOMDoc.DocumentElement.getElementsByTagName("ElementA").Item(0)

I get the following error message:

This indicates to me that the function is not returning the XML object, or that the the sub is not able to read the XML object into its own object variable.

Regrettably, I have not been able to find a way to inspect the contents of the object variable objDOMDoc to see if it actually contains an XML object.

Any help with this would be greatly appreciated.

1 Like

Hallo
Can you copy&paste such raw xml-content (without sensitive Data) protected by three ``` in seperate lines above and below the xml.

In general I would use python with third party lxml-library for the task.

Thank you for your response.

I do not think the XML is the problem. I am able to successfully read / write this XML file using the LibreOffice Basic function described here: How to get an XML element text in a LibreOffice Basic macro? In fact this is how the XML file was created.

Nevertheless, here it is:

<Root>
<ElementA>Text of ElementA</ElementA>
<ElementB>Text of ElementB</ElementB>
</Root>

It also does not work if I add the XML declaration like so:

<?xml version="1.0" encoding="UTF-8"?>
<Root>
<ElementA>Text of ElementA</ElementA>
<ElementB>Text of ElementB</ElementB>
</Root>

I think I may have found the problem. I’ll get back to you within a few minutes.

LibreOffice provides the XDocument interface, which supports almost the same methods as the MSXML2.DOMDocument60 object (and, unlike the latter, is multiplatform).
Here is an analogue of your function:

Option Explicit

Function GetXMLFromFile(Byval strFilePath As String) As Object
  Dim oDocBuilder
  On Error GoTo ErrHandler
  oDocBuilder=CreateUnoService("com.sun.star.xml.dom.DocumentBuilder")
  GetXMLFromFile=oDocBuilder.parseURI(ConvertToURL(strFilePath))
ErrHandler:
End Function

Sub Test
  Dim oXmlDoc
  oXmlDoc=GetXMLFromFile("C:\Temp\Sample.xml")
End Sub

See also section 15.12 “Importing and Exporting XML Files Using Calc” of the famous book by A. Pitonyak OOME_4_0.odt.

1 Like

… which is when DOM-based XML handling is needed. And there’s also SAX-based parser available.

@karolus Ultimately, the reason the function was failing was because I forgot a backslash in

objDOMDoc.Load("C:tmp\test1.xml")

It should have been

objDOMDoc.Load("C:\tmp\test1.xml")

But I’m actually glad that I made this mistake because through it I discovered something suprising:

Aparently, it is possible to call a function such as GetXMLFromFile that requires a parameter like strFilePath As String, forget to provide the parameter, and the LO Basic IDE doesn’t complain at all. If I try that in VBA, I get the following error:

@sokol92 Thank you very much, a multiplatform solution is much better than using MS.

By the way, @sokol92 , I have a question regarding this variable declaration. VBA programmers are encouraged to use specific data types when declaring variables, such as object, string or integer, instead of variant. I am seeing many examples in LO Basic where variables are implicitly declared as variant. Is this not a problem in LO Basic?

And a question about this instantiation.

In VBA, you would absolutely need to use the Set statement here: Set oDocBuilder = .

The official LibreOffice Basic documentation says the Set statement is optional (Set Statement).

The book by Andrew Pitonyak also says in Section 3.3.3. Assigning values to variables:

“The optional keyword Let may precede the variable name but serves no purpose other than readability. A similar optional keyword, Set, meant for Object variables, serves no purpose other than readability. These keywords are rarely used.”

Is this correct? If so, would it not be a good idea to remove the Set statement from the language? Why keep it if it serves no purpose?

Because removing it now would break old code. So everybody who used this in the last 25 years has to change code, also everybody who has this in a macro not written themselves…
.
IMHO, if you wish to have a modern language for programming, don’t use BASIC. But maybe I’m biased, as I never liked it that much…

1 Like

The argument was never used in the function.
It is true that Basic does not check if you provided all the parameters to functions (and in fact, it allows you to pass more than allowed, which is a clear bug) - neither when compiling, nor at runtime, until you actually access the arguments in the function. Only when you access them, the difference between optional and required arguments appears, and only when you use functions like IsMissing, IsError, etc.

You could create a bug report about missing compile-time check.

Andrew Pitonyak wrote about it this way:

What will happen to all old scripts using this statement after such a change?

I also mostly follow these guidelines in productive code. Only Long and not Integer. I think that A. Pitonyak’s remarks about the shortcomings of the as Object declaration mentioned by @JohnSUN do not apply to modern versions of LO (I started with 6.4).

One of the options for using Set is that we are writing code that is designed for both VBA and LO Basic. I know of such cases, how often it is used - it’s hard to say.

1 Like

That’s a valid point. In that case, I think the documentation should be updated to reflect the fact that this statement no longer has any functionality whatsoever and is only preserved to not break old code. Instead, the documentation goes into a lengthy description of its function and how/when to use it. This is misleading.

As well-meant as a small bit of advice like this may be, it doesn’t really help someone like me who has decades of experience with VBA and Visual Studio and almost zero with LibreOffice specifically and open source / Linux in general. What people like me need, and what most people seem reluctant to provide, is to step up and say, “Listen up. I’m an expert in developing LibreOffice extensions in Python and here is the setup that you need to have. You need to get this IDE, you need to install this SDK, you need to install these plugins, and you need to configure them in this way.” The endless options and flexibility of the open source / Linux ecology are daunting and confusing, not welcoming or refreshing.

Ah, so the LO Basic Object variable is not 100% compatible with UNO objects. That makes sense! Thanks for the information!

I had no idea that was a thing! :smiley:

That’s very interesting. If we can get some confirmation of this, I will suggest appropriate edits to the book to Andrew Pitonyak.

I had never heard of SAX until I recently started reading the book by Andrew Pitonyak. From what I read on the Internet today, I see that there is a SAX parser for VBA as well. My impression is that most VBA examples and tutorials focus on DOM.

Use CreateObject to get OLE objects on Windows.