Method XbpHTMLViewer2():queryByXPath() Foundation
Gets information about HTML elements.
:queryByXPath( <cQuery> ) --> oAsyncResult
A AsyncResult() object which can be used to wait for the query operation to complete, and for retrieving the operation result. The operation result is an array of DataObjects, one for each matching node in the DOM tree. When querying the complete document, the result is an array with a data object representing the document's root node. If the method fails, the returned AsyncResult object will be in error state. Use :error() to determine more information about the error.
The data objects returned at least have the members :nodeName, :nodeValue, :attributes, :childNodeCount and :children. Attributes are returned as members of a data object in :attributes, with the attribute values stored in a member with the same name as the attribute.
Using the method :queryByXPath(), a query can be performed against the DOM (document object model) tree of the current document for getting information about specific HTML elements. To do this, an XPath query string can be specified for selecting the desired elements. XPath is an expression language allowing the hierarchic addressing of nodes in a tree, see https://www.w3.org/TR/1999/REC-xpath-19991116.
The operation result of a query executed via :queryByXPath() is a read-only representation of the HTML elements matching the query expression. This can be used to check for the existence of certain HTML elements as well as for examining attribute values. Changing page elements via the operation result is not possible. Use :executeScript() or some other means to achieve this.
:queryByXPath() executes asynchronously in the context of the current page. The page must be fully loaded and the DOM tree must be stable for the method to function properly. If the HTML viewer is currently in the process of navigating to another page, for example, querying the DOM tree may fail or produce unexpected results. In this case, use the result object returned by :navigate() or the :navigateComplete() event to wait for navigation to complete before executing your query.
Example for using :queryByXPath()
// This example issues a query for a book in Amazon.com and returns
// information on the first item found. This is an examplary use-case
// for using XPath queries for locating known items in a known
// webpage loaded into a XbpHTMLViewer2 instance.
//
// Note that the queries in the example rely on the structure of the
// Amazon webpage, which may change over time!
#include "xbp.ch"
#define BOOK_ISBN "978-0618640157"
#define ISBN_SEARCH_URL "https://www.amazon.com/s?k="
#define CRLF Chr(13) + Chr(10)
PROCEDURE Main()
LOCAL oDlg
LOCAL oViewer2
LOCAL oSettings
LOCAL oData
LOCAL cUrl
SET CHARSET TO ANSI
// Create a form for hosting the HTML viewer object
oDlg := XbpDialog():new( AppDesktop() )
oDlg:taskList := .T.
oDlg:title := "XbpHTMLViewer2:queryByXPath() example"
oDlg:create( ,,, {640,480} )
CenterControl( oDlg )
// Create the HTML viewer object in the form's content area
oViewer2 := XbpHTMLViewer2():new( oDlg:drawingArea )
oViewer2:layoutAlign := XBPLAYOUT_LEFT + XBPLAYOUT_TOP + XBPLAYOUT_RIGHT + XBPLAYOUT_BOTTOM
oViewer2:create( ,, {10,10}, {600,420} )
// Change the user agent to a standard string. Amazon.com
// may not allow the search otherwise
oSettings := CoreWebView2Settings():new()
oSettings:UserAgent := "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"
oViewer2:setSettings( oSettings )
// Navigate to the results page on Amazon.com and extract
// information for the first item found
cUrl := ISBN_SEARCH_URL + BOOK_ISBN
oViewer2:navigate( cUrl ):wait()
oData := GetItemData( oViewer2 )
// Display the information in a message box
DisplayResults( oData )
oDlg:showModal()
oDlg:destroy()
RETURN
// Use XPath queries to extract ASIN, title and price information
// of the first book found. Return is a data object with the
// members :asin, :title and :price.
FUNCTION GetItemData( oViewer2 )
LOCAL oRet := DataObject():new()
LOCAL aRet
oRet:asin := ""
oRet:title := ""
oRet:price := ""
//
// This is the XPath query for the first search result:
// "//div[@data-component-type='s-search-result'][1]"
//
// The actual information like the book title is located in
// childs of this HTML element. Note that the used XPath
// queries heavily depend on the structure of the webpage
// that is examined!
//
// Get the ASIN which is specified as an attribute value
// and isn't visible to the user
aRet := oViewer2:queryByXPath( "//div[@data-component-type='s-search-result'][1][@data-asin and @role='listitem']" ):get()
IF .NOT. Empty(aRet)
oRet:asin := aRet[1]:attributes:getNoIvar("data-asin")
ENDIF
// Get the book title which is simple text in a child element
aRet := oViewer2:queryByXPath( "//div[@data-component-type='s-search-result'][1]//h2//span/text()" ):get()
IF .NOT. Empty(aRet)
oRet:title := aRet[1]:nodeValue
ENDIF
// Get the price which is simple text in a child element
aRet := oViewer2:queryByXPath( "//div[@data-component-type='s-search-result'][1]//span[@class='a-price']//span[@class='a-offscreen']/text()" ):get()
IF .NOT. Empty(aRet)
oRet:price := aRet[1]:nodeValue
ENDIF
RETURN oRet
PROCEDURE DisplayResults( oData )
LOCAL cMsg
IF Empty(oData:asin)
cMsg := "No book with ISBN " + BOOK_ISBN + " was found."
ELSE
cMsg := "Amazon Id (ASIN): " + oData:asin + CRLF +;
"Book Title: " + oData:title + CRLF +;
"Price: " + oData:price
ENDIF
MsgBox( cMsg, "First search result:" )
RETURN
PROCEDURE AppSys()
// Prevent creation of the default console window
RETURN
If you see anything in the documentation that is not correct, does not match your experience with the particular feature or requires further clarification, please use this form to report a documentation issue.