For Loop gives Object Required Error - vbscript

I am comparatively new to UFT as well as VB script.
I am trying to check innertext of divs inside For loop.
set getData = Browser("Browser").Page("Page").Object.getElementsByClassName("ClassName")
'Below line outputs 5'
msgbox getData.length-1
'output innertext for all these divs'
For i=0 to getData.length-1
msgbox getData(i).innertext
Next
This gives me Object Required Error on this line
msgbox getData(i).innertext
My first and 2nd element is blank while 3,4,5 are non-empty values.
When I write
msgbox getData(0).innertext
msgbox getData(1).innertext
msgbox getData(2).innertext
It gives me proper results
I further need to check this data against "Data" spreadsheet in UFT
Any pointers would be very much helpful.
Thanks,

Clarification needed:
As you would like to query div text, Is that any reason to use ClassName? If that so, you could use getElementsbyTagName instead getElementsByClassName.
However, I enhanced the code and adapting the query by any tag name option in the function. Here you go.
Dim objResultsDictionary
Set objResultsDictionary = GetTextContentFromHtmlTag(Browser("title:=Welcome: Mercury Tours").Page("title:=.*"),"div","")
Msgbox objResultsDictionary.Count
Result:8
Set objResultsDictionary = GetTextContentFromHtmlTag(Browser("title:=Welcome: Mercury Tours").Page("title:=.*"),"ClassName","mouseOut")
Msgbox objResultsDictionary.Count
Result = 11
Public Function GetTextContentFromHtmlTag(ByVal BrowserObject,ByVal TagName,ByVal TagValue)
Dim objDictionary
Dim objCollection
Set objDictionary = CreateObject("Scripting.Dictionary")
Select Case UCase(TagName)
Case "DIV"
Set objCollection = BrowserObject.Object.getElementsByTagName(TagName)
Case "CLASSNAME"
Set objCollection = BrowserObject.Object.getElementsByClassName(TagValue)
End Select
intDivCount = objCollection.Length
If intDivCount > 0 Then
For intCounter = 0 To intDivCount
If IsObject(objCollection(intCounter)) Then
strTagInnerText = objCollection(intCounter).innerText
If strTagInnerText <> "" Then
objDictionary.Add intCounter,strTagInnerText
End If
End If
Next
End If
Set GetTextContentFromHtmlTag = objDictionary
End Function
What you have to do:
You have to iterate the dictionary and get the innertext of the each tag.

Its giving you that error most probably because, there is various elements with the same class name other than the div or divs.
Try using some other properties.

Related

HP UFT/QTP 14.00, import CSV and maintain the values in data sheet

i'm importing some data from a csv file, here is the data:
*file.csv
UserName, EmailId, PhoneNumber
Antonio, anto#gmail.com, 1234567890
Oscar, osc#yahoo.com, 9999999999
Luis,lu#hotmail.com,8888888
I have a Function to call this file:
'************************************************************
Function ImportCsvFiletoDatatable(CsvFilePath,SheetName,HeaderDelimiter)
Dim filePath
Dim fso
Dim f
Dim fData
Dim arrData
Dim CsvValue
Dim CsvSheet
Dim CsvFirstLine
Dim CsvColumns
Dim ColumnIndex
Dim rIndex
Dim cIndex
filePath=CsvFilePath 'Specify file Path
'Open CSV File using File System Object
Set fso=createobject("scripting.filesystemobject")
Set f = fso.OpenTextFile(filePath)
CsvFirstLine=f.readline 'Treating like first line is the column names
CsvColumns=split(CsvFirstLine,HeaderDelimiter) 'Split the line using HeaderDelimiter
Set CsvSheet=DataTable.GetSheet(SheetName) 'Get the Specified sheet
'Add the splitted values as Datatable Columns
For ColumnIndex=lbound(CsvColumns) to ubound(CsvColumns)
CsvSheet.addparameter CsvColumns(ColumnIndex),""
Next
While not f.AtEndOfStream
rIndex=f.Line-1 'Specify Row index
fData=f.ReadLine ' Read CSV File Line
arrData=split(fData,",") 'Split the line
cIndex=1 'Specify Column Index
CsvSheet.SetCurrentRow(rIndex) 'Set Row in the Datatable
' Add values in Datatable
For Each CsvValue In arrData
CsvSheet.getparameter(cIndex).value=CsvValue
cIndex=cIndex+1
Next
Wend
f.Close
Set fso=Nothing
End Function
'************************************************************
And works well, but the information is volatile, and i can't manage, or use the data.
Someone know how to keep the data in the data sheet, although leave UFT?
Dim objQtApp, strXlsPath
strXlsPath = Environment("TestDir") & "\Default.xls"
Set objQtApp = CreateObject("QuickTest.Application")
DataTable.Export strXlsPath
objQtApp.Test.DataTable.Import strXlsPath
Set objQtApp = Nothing
The Design Time DataTable is found in the Default.xls. This is loaded when you open a test case or if you edit it manually from UFT. In case you want to refresh it programmatically use the code-snippet above. Export and then with AUtomation Object Import.
Of course put it into a method and call from whatever place is convenient for you.
If you want UFT to take care of it automatically, Create a new Class and a singleton Instance of it.
Implement the Class_Terminate method of the class and put the code there. WHenever UFT exits either because of a crash or or a nomral test run ends, it will try to clean up all Objects created while running. This object will be among them, and as a part of the automatic cleanup process you will save your runtime datatable into the design-time one(Default.xls) and then reload it.

Assign Attachment Field To Variable in Access 2010

I'm trying to understand how to work with the new Attachment field that is available in Access 2010. I would like to assign the value from the table directly into a variable. I know that I can do this if I use an intermediary form, but this seems like sloppy coding to rely on a form in order to grab a value from a table. Is there some way to grab what is in an attachment field and assign it directly to a variable? I have multiple instances where this would be handy for me. The first instance is I want to grab a photo stored in an attachment field to assign to the ribbon. A second instance is to load a company logo from a table into a variable and keep it in memory to use throughout the program as needed.
The code I have so far is this, but it gives me a type mismatch error:
Dim ParentRS As Recordset, ChildRS As Recordset, Img As Attachment
Set ParentRS = CurrentDb.OpenRecordset("SELECT * FROM LtblImg;", dbOpenSnapshot)
If ParentRS.RecordCount > 0 Then
Set ChildRS = ParentRS("Img").Value
If ChildRS.RecordCount > 0 Then
Set Img = ChildRS("FileData")
End If
ChildRS.Close
End If
ParentRS.Close
Yes, Dim Img As Attachment looks tempting, but Attachment (which is actually Access.Attachment) refers to an Attachment control that could be used on a form (just like Access.TextBox) and does not appear to be suitable for your intended purpose.
The only native VBA type for storing this sort of binary data is an array of Byte values, but often when dealing with byte arrays we wind up looping through and processing them byte-by-byte, which is tedious and inefficient.
You might consider using a binary ADODB.Stream object as your "variable". You could create a function to retrieve the attachment bytes and return them in a Stream like so
Option Compare Database
Option Explicit
Public Function GetLogoAsStream() As ADODB.Stream
Dim cdb As DAO.Database, rstMain As DAO.Recordset, rstAttach As DAO.Recordset2, fldAttach As DAO.Field2
' Project references required for early binding:
' Windows Script Host Object Model
' Microsoft ActiveX Data Objects 2.8 Library
Dim fso As FileSystemObject, tempFileSpec As String
Static strm As ADODB.Stream
If strm Is Nothing Then
Set fso = New FileSystemObject
tempFileSpec = fso.GetSpecialFolder(TemporaryFolder) & "\" & fso.GetTempName
Set fso = Nothing
Set cdb = CurrentDb
Set rstMain = cdb.OpenRecordset( _
"SELECT [AttachmentFiles] " & _
"FROM [AttachmentsTable] " & _
"WHERE [Description]='SO logo'", _
dbOpenSnapshot)
Set rstAttach = rstMain("AttachmentFiles").Value
' make sure we use the correct file extension
tempFileSpec = tempFileSpec & "." & rstAttach.Fields("FileType").Value
Set fldAttach = rstAttach.Fields("FileData")
fldAttach.SaveToFile tempFileSpec
Set fldAttach = Nothing
rstAttach.Close
Set rstAttach = Nothing
rstMain.Close
Set rstMain = Nothing
Set cdb = Nothing
Set strm = New ADODB.Stream
strm.Type = adTypeBinary
strm.Open
strm.LoadFromFile tempFileSpec
Kill tempFileSpec
End If
strm.Position = 0
Set GetLogoAsStream = strm
End Function
and then if you had, say, a Report like this with an empty Image control
and an On Load event procedure like this to load the Image control's .PictureData from your "variable" (actually a Function returning an ADODB.Stream)
Private Sub Report_Load()
Me.LogoImage.PictureData = GetLogoAsStream.Read
End Sub
it could produce something like this

How to read and write non-standard document properties of word file in vbscript?

Microsoft Word is offering some default document properties to be set in Word documents.
There is a number of default properties, for which vbscript has constants.
But Word (2011) is offering some more properties, e.g. companyfaxnumber, publishingdate,keywords.
There is a possibility to access the builtin properties by calling
Set oWord = CreateObject("Word.Application")
oWord.Visible = True
oWord.Documents.Open(strFilePath)
For Each prop In oWord.ActiveDocument.BuiltInDocumentProperties
WScript.Echo prop.Name + "::" + oWord.ActiveDocument.BuiltInDocumentProperties(prop.Name).Value
Next
But how do i find the names of the "custom" properties that are offered by word, but are not present in vbscript as constant?
There is the function
Document.CustomDocumentProperties
But if i do a listing like the one above, i get properties named info1, info2, etc.
Too access the Word CustomDocumentProperties, you will need to be able to access the OLE File Property Reader. This expands beyond the normal/simple document properties because it allows you too add custom properties as well.
There is a Tales from the Script article from 2005 detailing the installation and usage of utilizing CustomDocumentProperties within Word -> Here
For the download to install the OLE Property Reader DLL, Go -> Here
Here is an example of property set/get once the property read is installed:
Const msoPropertyTypeBoolean = 2
Set objFile = CreateObject("DSOFile.OleDocumentProperties")
objFile.Open("C:\Scripts\New_users.xls")
'Set
'=======================================================================
objFile.CustomProperties.Add "Document Reviewed", msoPropertyTypeBoolean
objFile.Save
'Get
'=======================================================================
Set objProperty = objFile.CustomProperties.Item("Document Reviewed")
wscript.echo objProperty.Value
Enjoy!
Hi recently figured out how to get there myself:
The Word "Frontend Editor" is cheating on the document properties. There is a hard defined set of properties like author,category, keywords etc.
The additional properties offered by the editor are so called custom properties which are defined in an external XML structure inside the docx-container.
So there is no easy vbscript function to modify the values of these custom properties.
Thanks to the web, someone did some hacking and this is the solution for it:
Sub WriteCustomCoverProperties(ByRef wordInstance, strProp, strText)
Dim oCustPart
Dim oNode
Dim strXPath
strProp = Replace(strProp, " ", "")
Select Case strProp
Case "Abstract" strXPath = "/ns0:CoverPageProperties[1]/ns0:Abstract[1]"
Case "PublishDate" strXPath = "/ns0:CoverPageProperties[1]/ns0:PublishDate[1]"
Case "CompanyAddress" strXPath = "/ns0:CoverPageProperties[1]/ns0:CompanyAddress[1]"
Case "CompanyPhone" strXPath = "/ns0:CoverPageProperties[1]/ns0:CompanyPhone[1]"
Case "CompanyFax" strXPath = "/ns0:CoverPageProperties[1]/ns0:CompanyFax[1]"
Case "CompanyEmail" strXPath = "/ns0:CoverPageProperties[1]/ns0:CompanyEmail[1]"
Case Else
Exit Sub
End Select
Set oCustPart = wordInstance.ActiveDocument.CustomXMLParts(3)
Set oNode = oCustPart.SelectSingleNode(strXPath)
oNode.Text = strText
Set oCustPart = Nothing
Set oNode = Nothing
End Sub
May it be of help =)

VBScript: XPath Query with multiple namespaces

What XPath query should I use to get to the GetLogisticsOfferDateResult Node?
I have attached the vbscript that I'm using.
I suspect the problem has to do with the multiple namespaces in the document. But how do I reference the second namespace in the XPath?
Dim responseXML
responseXML = '"<s:Envelope xmlns:s=""http://schemas.xmlsoap.org/soap/envelope/""><s:Body><GetLogisticsOfferDateResponse xmlns=""http://schneider-electric.com/OrderEntryService""><GetLogisticsOfferDateResult>2010-07-20</GetLogisticsOfferDateResult></GetLogisticsOfferDateResponse></s:Body></s:Envelope>"'
Dim responseDoc
Set responseDoc = WScript.CreateObject("MSXML2.DOMDocument.6.0")
responseDoc.loadXML(responseXML)
responseDoc.setProperty "SelectionNamespaces", "xmlns:s='http://schemas.xmlsoap.org/soap/envelope/'"
Dim requestedNode
'This node is not found
'Set requestedNode = responseDoc.selectSingleNode("//s:Envelope//s:Body//GetLogisticsOfferDateResponse//GetLogisticsOfferDateResult")
'This node is found
Set requestedNode = responseDoc.selectSingleNode("//s:Envelope//s:Body")
'This node is found
'Set requestedNode = responseDoc.selectSingleNode("//s:Envelope")
If requestedNode Is Nothing Then
WScript.Echo "Node not found"
Else
WScript.Echo requestedNode.text
End If
Set responseDoc = Nothing
Set LODateNode = Nothing
Turns out my setting of selectionNamespaces had to be as follows:
responseDoc.setProperty "SelectionNamespaces", "xmlns:sc='http://schneider-electric.com/OrderEntryService' xmlns:s='http://schemas.xmlsoap.org/soap/envelope/'"
Then the XPath query had to be:
Set requestedNode = responseDoc.selectSingleNode("//s:Envelope//s:Body//sc:GetLogisticsOfferDateResponse//sc:GetLogisticsOfferDateResult")
You have not defined the default namespace of the document (http://schneider-electric.com/OrderEntryService) in your code.
responseDoc.setProperty "SelectionNamespaces", "'http://schemas.xmlsoap.org/soap/envelope/' 'http://schneider-electric.com/OrderEntryService'"
You will either need to add it, or prefix the elements that belong to it with it.

Sorting a collection in classic ASP

It's quite a simple question - how do I sort a collection?
I've got a CSV file with rows in a random order. I'd like to sort the rows according to the date in one column. Do I add the rows to a recordset? Can I sort with a Scripting.Dictionary?
I've clearly been spoilt with .NET and Linq, and now I find myself back in the land of classic asp, realising I must have known this 7 years ago, and missing generics immensely. I feel like a complete n00b.
In this case I would get help from big brother .net. It's possible to use System.Collections.Sortedlist within your ASP app and get your key value pairs sorted.
set list = server.createObject("System.Collections.Sortedlist")
with list
.add "something", "YY"
.add "something else", "XX"
end with
for i = 0 to list.count - 1
response.write(list.getKey(i) & " = " & list.getByIndex(i))
next
Btw if the following .net classes are available too:
System.Collections.Queue
System.Collections.Stack
System.Collections.ArrayList
System.Collections.SortedList
System.Collections.Hashtable
System.IO.StringWriter
System.IO.MemoryStream;
Also see: Marvels of COM .NET interop
I'd go with the RecordSet approach. Use the Text Driver. You'll need to change the directory in the connection string and the filename in the select statement. the Extended Property "HDR=Yes" specifies that there's a header row in the CSV which I suggest as it will make writing the psuedo SQL easier.
<%
Dim strConnection, conn, rs, strSQL
strConnection = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\inetpub\wwwroot\;Extended Properties='text;HDR=Yes;FMT=Delimited';"
Set conn = Server.CreateObject("ADODB.Connection")
conn.Open strConnection
Set rs = Server.CreateObject("ADODB.recordset")
strSQL = "SELECT * FROM test.csv order by date desc"
rs.open strSQL, conn, 3,3
WHILE NOT rs.EOF
Response.Write(rs("date") & "<br/>")
rs.MoveNext
WEND
rs.Close
Set rs = Nothing
conn.Close
Set conn = Nothing
%>
It's been a long time for me too. IIRC you don't have an option out of the box.
If I were you I'd put all the data in an array and then sort the array. I found a QuickSort implementation here: https://web.archive.org/web/20210125130007/http://www.4guysfromrolla.com/webtech/012799-3.shtml
Also look at the "Bubble Sort", works excellent with those classic asp tag cloud.
https://web.archive.org/web/20180927040044/http://www.4guysfromrolla.com:80/webtech/011001-1.shtml
A late late answer to this, but still of value.
I was working with small collections so could afford the approach where I inserted the item in the correct place on each occasion, effectively reconstructing the collection on each addition.
The VBScript class is as follows:
'Simple collection manager class.
'Performs the opration of adding/setting a collection item.
'Encapulated off here in order to delegate responsibility away from the collection class.
Class clsCollectionManager
Public Sub PopulateCollectionItem(collection, strKey, Value)
If collection.Exists(strKey) Then
If (VarType(Value) = vbObject) Then
Set collection.Item(strKey) = Value
Else
collection.Item(strKey) = Value
End If
Else
Call collection.Add(strKey, Value)
End If
End Sub
'take a collection and a new element as input parameters, an spit out a brand new collection
'with the new item iserted into the correct location by order
'This works on the assumption that the collection it is receiving is already ordered
'(which it should be if we always use this method to populate the item)
'This mutates the passed collection, so we highlight this by marking it as byref
'(this is not strictly necessary as objects are passed by reference anyway)
Public Sub AddCollectionItemInOrder(byref existingCollection, strNewKey, Value)
Dim orderedCollection: Set orderedCollection = Server.CreateObject("Scripting.Dictionary")
Dim strExistingKey
'If there is something already in our recordset then we need to add it in order.
'There is no sorting available for a collection (or an array) in VBScript. Therefore we have to do it ourself.
'First, iterate over eveything in our current collection. We have to assume that it is itself sorted.
For Each strExistingKey In existingCollection
'if the new item doesn't exist AND it occurs after the current item, then add the new item in now
'(before adding in the current item.)
If (Not orderedCollection.Exists(strNewKey)) And (strExistingKey > strNewKey) Then
Call PopulateCollectionItem(orderedCollection, strNewKey, Value)
End If
Call PopulateCollectionItem(orderedCollection, strExistingKey, existingCollection.item(strExistingKey))
Next
'Finally check to see if it still doesn't exist.
'It won't if the last place for it is at the very end, or the original collection was empty
If (Not orderedCollection.Exists(strNewKey)) Then
Call PopulateCollectionItem(orderedCollection, strNewKey, Value)
End If
Set existingCollection = orderedCollection
End Sub
End Class

Resources