Text File compare in “WDIFF” style (QTP, VBScript, XML, XSL)

Posted by Albert Gareev on May 26, 2009 | Categories: Source codeText DataXML Data

Original date: 26 Jan 2009, 1:30pm

Line by line, and word by word comparison isn’t a big problem. But how conveniently show the results?
With WinRunner comparison and reporting has been implemented utilizing WDIFF program.
With QTP we can do the same using XML-XSL technology.

The function below performs comparison of 2 text files generating output in XML keeping the original structure and format of both files.
As a live example, uploaded files are the text files and the resulting XML generated.

1.txt, 2.txt, 1.xml

File instructions: Download, save. Rename to “temp.rar”. Extract the archive. Save to “C:\Temp\” the following extracted files: “1.txt”, “2.txt”, “1.xml”. Now you can use Notepad to see the contents of the files.

XML file will not be displayed as a regular web-page until you define transformation rules (XSL) for it.

See sample version of XSL transformation script I use in the next blog post.

Function libraries used:

Service Functions – String (QTP, VBScript)

Service Functions – XML (QTP, VBScript)

Sample – using the function:

sOutputFile = TextFileCompare("c:\temp\1.txt", "c:\temp\2.txt", "c:\temp", Nothing)

Main function

Public Function TextFileCompare(ByVal sFile1, ByVal sFile2, ByVal sOutputFolder, ByVal objParameter)
Dim boolRC, boolCmp
Dim FSO, sOutput, sOutputFile
Dim objFile1, objFile2, objXMLOutput, objRoot
Dim intLineCount1, intLineCount2
Dim objHead, objBody, objText, objLine
Dim objColl, Iter
Dim sLine1, sLine2

 'Verify both files exist
Set FSO = CreateObject("Scripting.FileSystemObject")

boolRC = FSO.FileExists(sFile1)
If Not boolRC Then
TextFileCompare = ""
Set FSO = Nothing
Exit Function
End If
boolRC = FSO.FileExists(sFile2)
If Not boolRC Then
TextFileCompare = ""
Set FSO = Nothing
Exit Function
End If

'Take output file name (as sFile1 with no extension) and form it as XML
sOutputFile = FSO.GetBaseName(sFile1) & ".xml"
'Full path output
sOutput = sOutputFolder & "\" & sOutputFile

'Create output file
Set objXMLOutput = XMLUtil.CreateXML("output")
Set objRoot = objXMLOutput.GetRootElement

'Create head section (stats)
objRoot.AddChildElementByName "head", ""
Set objColl = objRoot.ChildElementsByPath("./head")
Set objHead = objColl.Item(objColl.Count)

'Create body section (text)
objRoot.AddChildElementByName "body", ""
Set objColl = objRoot.ChildElementsByPath("./body")
Set objBody = objColl.Item(objColl.Count)

'Create text output node
objBody.AddChildElementByName "text", ""
Set objColl = objBody.ChildElementsByPath("./text")
Set objText = objColl.Item(objColl.Count)

'Open files
Set objFile1 = FSO.OpenTextFile(sFile1, 1)
Set objFile2 = FSO.OpenTextFile(sFile2, 1)

boolCmp = TRUE
intLineCount1 = 0
intLineCount2 = 0

'Loop through files
Do While TRUE

'create child node (Line)
objText.AddChildElementByName "line", ""
Set objColl = objText.ChildElementsByPath("./line")
Set objLine = objColl.Item(objColl.Count)

'Get next pair of lines
boolRC = objFile1.AtEndOfStream
If boolRC Then
sLine1 = ""
sLine1 = objFile1.ReadLine()
intLineCount1 = intLineCount1 + 1
End If
boolRC = objFile2.AtEndOfStream
If boolRC Then
sLine2 = ""
sLine2 = objFile2.ReadLine()
intLineCount2 = intLineCount2 + 1
End If

boolCmp = boolCmp AND LineCompare(objLine, sLine1, sLine2, objParameter)

'Shift down performed automatically

'Exit condition
If objFile1.AtEndOfStream AND objFile2.AtEndOfStream Then
Exit Do
End If


If  boolCmp Then
TextFileCompare = TRUE
objText.AddAttribute "status", "MATCH"
TextFileCompare = FALSE
objText.AddAttribute "status", "MISMATCH"
End If
'File stats
objHead.AddChildElementByName "file1", sFile1
objHead.AddChildElementByName "file2", sFile2
objHead.AddChildElementByName "linecount1", CStr(intLineCount1)
objHead.AddChildElementByName "linecount2", CStr(intLineCount2)

Set objColl = objText.ChildElementsByPath("descendant::line[@status='MISMATCH']")
objHead.AddChildElementByName "linefailcount", CStr(objColl.Count)
Set objColl = objText.ChildElementsByPath("descendant::word[@status='MISMATCH']")
objHead.AddChildElementByName "wordfailcount", CStr(objColl.Count)

'Save XML
objXMLOutput.SaveFile sOutput

'Close and free
Set objFile1 = Nothing
Set objFile2 = Nothing
Set FSO = Nothing
Set objXMLOutput = Nothing

'Return output file name
TextFileCompare = sOutput

End Function

Text Line Processing

Private Function LineCompare(ByRef objLine, ByVal sLine1, ByVal sLine2, ByVal objParameter)
Dim boolRC
Dim dvLine1, dvLine2
Dim objColl, objWord, objNode
Dim Iter, Idx, sWord1, sWord2, sIndent1, sIndent2, sEmpty

sEmpty = ""
If sLine1 = "" Then sEmpty = "Src"
If sLine2 = "" Then sEmpty = sEmpty & " Dest"

dvLine1 = Split(ReplaceEx(Trim(sLine1), " +", " ", TRUE), " ")
dvLine2 = Split(ReplaceEx(Trim(sLine2), " +", " ", TRUE), " ")

Iter = 0
boolRC = TRUE

  Do While TRUE
'create child node (Word)
objLine.AddChildElementByName "word", ""
Set objColl = objLine.ChildElementsByPath("./word")
Set objWord = objColl.Item(objColl.Count)

'Get next pair of words
If Iter > UBound(dvLine1) Then
sWord1 = ""
sIndent1 = ""
sWord1 = dvLine1(Iter)
Idx = InStr(sLine1, sWord1)
sIndent1 = Left(sLine1, Idx-1)
sLine1 = Mid(sLine1, Idx + Len(sWord1) )
End If
If Iter > UBound(dvLine2) Then
sWord2 = ""
sIndent2 = ""
sWord2 = dvLine2(Iter)
Idx = InStr(sLine2, sWord2)
sIndent2 = Left(sLine2, Idx-1)
sLine2 = Mid(sLine2, Idx + Len(sWord2))
End If

boolRC = boolRC AND WordCompare(objWord, sWord1, sWord2, objParameter)

'Store indents
Set objNode = ChildElementByName(objWord, "src")
sIndent1 = Replace(sIndent1, " ", "_")
objNode.AddAttribute "indent", sIndent1
Set objNode = ChildElementByName(objWord, "dest")
sIndent2 = Replace(sIndent2, " ", "_")
objNode.AddAttribute "indent", sIndent2

'Shift right
Iter = Iter + 1

'Exit condition
If (Iter > UBound(dvLine1)) AND (Iter > UBound(dvLine2)) Then
Exit Do
End If

If  sEmpty <> "" Then
objLine.AddAttribute "empty", sEmpty
End If

If  boolRC Then
LineCompare = TRUE
objLine.AddAttribute "status", "MATCH"
LineCompare = FALSE
objLine.AddAttribute "status", "MISMATCH"
End If

End Function

 Word Comparison

Private Function WordCompare(ByRef objWord, ByVal sWord1, ByVal sWord2, ByVal objParameter)
Dim boolRC

objWord.AddChildElementByName "src", sWord1
objWord.AddChildElementByName "dest", sWord2

boolRC = sWord1 = sWord2

If  boolRC Then
WordCompare = TRUE
objWord.AddAttribute "status", "MATCH"
WordCompare = FALSE
objWord.AddAttribute "status", "MISMATCH"
End If

End Function

  • 2 responses to "Text File compare in “WDIFF” style (QTP, VBScript, XML, XSL)"

  • Gowthaman
    12th August 2013 at 11:37

    Can you please explain, what are the mandatory functions that I need to take to use this text file comparision?

    [Albert’s reply: Gowthaman, look in String and XML libraries referred via links.]

  • Nagireddygv
    13th March 2015 at 7:56

    Hi Team,

    Kindly let me know, “Text Line Processing”, function , what is the purpose of adding “ReplaceEx”, Whilst Splitting, Please help me ..

    [Albert’s comment. The purpose of ReplaceEx is to get rid of possible extra space chars before splitting.]

Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported
This work by Albert Gareev is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported.