Automation Beyond

Testing and Test Automation for Software Quality Assurance. Above Requirements. Beyond Expectations. Methodologies and concepts. Framework Design. Programming and Scripting. Created by Albert Gareev.

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

Posted by Albert Gareev on 2009/05/26

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 function call:

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

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

  1. [...] Refer to Text File Compare functions used to see how XML file is generated [...]

  2. [...] It’s very convenient to generate and store execution logs in XML format. That could be Test Execution Logs, File Comparison Logs, Data Processing Logs, anything [...]

  3. [...] After line by line (and word by word) text file comparison has been performed, XML log was produced [...]

  4. [...] The example below is taken from my Text File Compare sample solution [...]

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <pre> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>