impulsgraw
impulsgraw

Reputation: 897

Implementing HTMLBaseElement in excel vba

I need to get an element from html code using it's xpath. I'm using "standart coded function" for that

Public Function getXPathElement(sXPath As String, objElement As Object) As 

HTMLBaseElement
    Dim sXPathArray() As String

    Dim sNodeName As String
    Dim sNodeNameIndex As String
    Dim sRestOfXPath As String
    Dim lNodeIndex As Long
    Dim lCount As Long

     ' Split the xpath statement
    sXPathArray = Split(sXPath, "/")
    sNodeNameIndex = sXPathArray(1)
    If Not InStr(sNodeNameIndex, "[") > 0 Then
        sNodeName = sNodeNameIndex
        lNodeIndex = 1
    Else
        sXPathArray = Split(sNodeNameIndex, "[")
        sNodeName = sXPathArray(0)
        lNodeIndex = CLng(Left(sXPathArray(1), Len(sXPathArray(1)) - 1))
    End If
    sRestOfXPath = Right(sXPath, Len(sXPath) - (Len(sNodeNameIndex) + 1))

    Set getXPathElement = Nothing
    For lCount = 0 To objElement.ChildNodes().Length - 1
        If UCase(objElement.ChildNodes().Item(lCount).nodeName) = UCase(sNodeName) Then
            If lNodeIndex = 1 Then
                If sRestOfXPath = "" Then
                    Set getXPathElement = objElement.ChildNodes().Item(lCount)
                Else
                    Set getXPathElement = getXPathElement(sRestOfXPath, objElement.ChildNodes().Item(lCount))
                End If
            End If
            lNodeIndex = lNodeIndex - 1
        End If
    Next lCount
End Function

But when i'm trying to execute it with the following code

Dim elem As HTMLBaseElement
Dim oHTML As New HTMLDocument

oHTML.body.innerHTML = GetHTML("http://ya.ru")

Set elem = getXPathElement("/html/body/table/", oHTML)

MsgBox elem.InnerText

... it just breaks up with "Object variable or With block not set" error. I also tried to implement elem variable with

Set elem = New HTMLBaseElement

... but Excel told me "Invalid use of New keyword". Debugging that process I found out that elem var always equals to nothing. :/

Just in case, I have MS Office 2013, and yes, I checked up my References.

Upvotes: 1

Views: 1714

Answers (1)

David Zemens
David Zemens

Reputation: 53623

In this loop, you need to exit the loop upon assignment of a return value:

For lCount = 0 To objElement.ChildNodes().Length - 1
    If UCase(objElement.ChildNodes().Item(lCount).nodeName) = UCase(sNodeName) Then
        If lNodeIndex = 1 Then
            If sRestOfXPath = "" Then
                Set getXPathElement = objElement.ChildNodes().Item(lCount)
            Else
                Set getXPathElement = getXPathElement(sRestOfXPath, objElement.ChildNodes().Item(lCount))
            End If
        End If
        lNodeIndex = lNodeIndex - 1
    End If
Next lCount

Should become:

For lCount = 0 To objElement.ChildNodes().Length - 1
    If UCase(objElement.ChildNodes().Item(lCount).nodeName) = UCase(sNodeName) Then
        If lNodeIndex = 1 Then
            If sRestOfXPath = "" Then
                Set getXPathElement = objElement.ChildNodes().Item(lCount)
                Exit For
            Else
                Set getXPathElement = getXPathElement(sRestOfXPath, objElement.ChildNodes().Item(lCount))
                Exit For
            End If
        End If
        lNodeIndex = lNodeIndex - 1
    End If
Next lCount

NOTE: You should probably still test for Nothing-ness to avoid unhandled errors, e.g.:

Set elem = getXPathElement("/html/body/table/", oHTML)
If elem Is Nothing Then
    MsgBox "Error!", vbINformation
    Exit Sub 'etc...
End If
MsgBox elem.InnerText

Upvotes: 3

Related Questions