Text File compare in “WDIFF” style (QTP, VBScript, XML, XSL)
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.
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 = "" Else sLine1 = objFile1.ReadLine() intLineCount1 = intLineCount1 + 1 End If boolRC = objFile2.AtEndOfStream If boolRC Then sLine2 = "" Else sLine2 = objFile2.ReadLine() intLineCount2 = intLineCount2 + 1 End If 'Compare 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 Loop If boolCmp Then TextFileCompare = TRUE objText.AddAttribute "status", "MATCH" Else 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 objFile1.Close objFile2.Close 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 = "" Else 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 = "" Else sWord2 = dvLine2(Iter) Idx = InStr(sLine2, sWord2) sIndent2 = Left(sLine2, Idx-1) sLine2 = Mid(sLine2, Idx + Len(sWord2)) End If 'Compare 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 Loop If sEmpty <> "" Then objLine.AddAttribute "empty", sEmpty End If If boolRC Then LineCompare = TRUE objLine.AddAttribute "status", "MATCH" Else 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" Else WordCompare = FALSE objWord.AddAttribute "status", "MISMATCH" End If End Function
2 responses to "Text File compare in “WDIFF” style (QTP, VBScript, XML, XSL)"
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.]
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.]