windows-nt/Source/XPSP1/NT/admin/pchealth/authtools/prodtools/searchtester/xpquery.cls
2020-09-26 16:20:57 +08:00

447 lines
14 KiB
OpenEdge ABL

VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
Persistable = 0 'NotPersistable
DataBindingBehavior = 0 'vbNone
DataSourceBehavior = 0 'vbNone
MTSTransactionMode = 0 'NotAnMTSObject
END
Attribute VB_Name = "XPQuery"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit
Dim m_oDocQTpl As DOMDocument
Dim m_oDocStw As DOMDocument
Dim m_oHsc_query_template_Node As IXMLDOMNode, _
m_o_Query_Term_Node As IXMLDOMNode, _
m_oHsc_qtn_as As IXMLDOMNode
Dim m_o_epilogue As IXMLDOMNode
Dim m_odictStopSigns As Scripting.Dictionary
Const STOPSIGN_AT_END_OF_WORD As Long = 3
Const STOPSIGN_ANYWHERE As Long = 0
Private Sub Class_Initialize()
Set m_oDocQTpl = New DOMDocument
End Sub
Function Init( _
ByRef strQTpl As String, _
ByRef oDomtaxo As DOMDocument _
) As Boolean
Init = False
oDomtaxo.setProperty "SelectionLanguage", "XSLPattern"
Dim oDomNode As IXMLDOMNode
LoadStopSigns oDomtaxo
Set oDomNode = oDomtaxo.selectSingleNode("METADATA/STOPWORD_ENTRIES")
Set m_oDocStw = New DOMDocument
m_oDocStw.loadXML oDomNode.xml
Init = True
Common_Exit:
Exit Function
End Function
Sub LoadStopSigns(ByRef oDomtaxo As DOMDocument)
Dim oDomNode As IXMLDOMNode, oNodeList As IXMLDOMNodeList
Set m_odictStopSigns = New Scripting.Dictionary
Dim l As Long
Set oNodeList = oDomtaxo.selectNodes("/METADATA/STOPSIGN_ENTRIES/*")
For Each oDomNode In oNodeList
If (oDomNode.Attributes.getNamedItem("CONTEXT").Text = "ENDOFWORD") Then
l = STOPSIGN_AT_END_OF_WORD
Else
l = STOPSIGN_ANYWHERE
End If
m_odictStopSigns.Add oDomNode.Attributes.getNamedItem("STOPSIGN").Text, l
Next
End Sub
Function GetXPathQuery( _
strQTpl As String, _
ByVal strQuery As String, _
Optional ByRef out_dictStopSigns As Scripting.Dictionary, _
Optional ByRef out_dictStopWords As Scripting.Dictionary, _
Optional ByRef out_strCanonicalQuery, _
Optional ByRef out_strXpathAutoStringifyQuery As String, _
Optional ByRef out_strAutoStringifyQuery As String _
) As String
GetXPathQuery = ""
m_oDocQTpl.loadXML strQTpl
If (m_oDocQTpl.parseError.errorCode <> 0) Then
Err.Raise vbObjectError + 9999, "GetXPathQuery", "Could not load Query Template"
End If
Set m_oHsc_query_template_Node = m_oDocQTpl.selectSingleNode("/hsc-query-template/template")
Set m_o_epilogue = m_oHsc_query_template_Node.selectSingleNode("epilogue")
Set m_o_Query_Term_Node = m_oHsc_query_template_Node.selectSingleNode("query-term")
m_oHsc_query_template_Node.removeChild m_o_Query_Term_Node
Dim oQTNode As IXMLDOMNode, _
oDomText As IXMLDOMText
strQuery = LCase$(Trim$(strQuery))
Dim cQuote As String
' If (InStr(strQuery, "'") > 0) Then
' cQuote = "'"
' Else
' cQuote = """"
' End If
cQuote = """"
' First let's see whether this is an unterminated Query String
If (IsUnTerminatedQuotedQuery(strQuery, cQuote)) Then
strQuery = strQuery + cQuote
End If
GetRidOfStopSignsAndMultipleWhiteSpaces strQuery, out_dictStopSigns
If (IsStringifiableQuery(strQuery)) Then
Set m_oHsc_qtn_as = m_oHsc_query_template_Node.cloneNode(deep:=True)
Set oQTNode = m_o_Query_Term_Node.cloneNode(deep:=True)
Set oDomText = m_oDocQTpl.createTextNode("""" + strQuery + """")
oQTNode.selectSingleNode("in-argument").appendChild oDomText
m_oHsc_qtn_as.insertBefore oQTNode, m_oHsc_qtn_as.selectSingleNode("epilogue")
out_strXpathAutoStringifyQuery = m_oHsc_qtn_as.Text
Set m_oHsc_qtn_as = Nothing
out_strAutoStringifyQuery = oDomText.Text
Else
out_strXpathAutoStringifyQuery = ""
out_strAutoStringifyQuery = ""
End If
If (Not out_dictStopWords Is Nothing) Then out_dictStopWords.RemoveAll
out_strCanonicalQuery = ""
Dim iQTcount As Integer: iQTcount = 0 'Counts the Tokens
Dim oTokens As Tokenizer: Set oTokens = New Tokenizer
oTokens.Init strQuery
Dim strToken As String, bIsString As Boolean
Do While (Not oTokens.eof)
DoEvents
strToken = oTokens.NextWordOrString(bIsString)
If (IsStopWord(strToken)) Then
If (Not out_dictStopWords.Exists(strToken)) Then
out_dictStopWords.Add strToken, strToken
End If
Else
iQTcount = iQTcount + 1
If (bIsString) Then
out_strCanonicalQuery = out_strCanonicalQuery + """" + strToken + """" + " "
Else
out_strCanonicalQuery = out_strCanonicalQuery + strToken + " "
End If
Set oQTNode = m_o_Query_Term_Node.cloneNode(True)
Set oDomText = m_oDocQTpl.createTextNode("""" + strToken + """")
oQTNode.selectSingleNode("in-argument").appendChild oDomText
If (iQTcount > 1) Then
Set oDomText = m_oDocQTpl.createTextNode("and")
m_oHsc_query_template_Node.insertBefore oDomText, m_o_epilogue
End If
m_oHsc_query_template_Node.insertBefore oQTNode, m_o_epilogue
End If
' GetXPathQuery = GetXPathQuery + " " + Replace(txtQTpl, "%qa%", oTokens.NextWord)
Loop
If (iQTcount > 0) Then
GetXPathQuery = m_oHsc_query_template_Node.Text
Else
GetXPathQuery = ""
End If
End Function
Private Function IsUnTerminatedQuotedQuery(strQuery As String, cQuote As String) As Boolean
IsUnTerminatedQuotedQuery = ((Left$(strQuery, 1) = cQuote) And (Right$(strQuery, 1) <> cQuote))
End Function
Private Function IsStringifiableQuery(ByVal strQuery As String, Optional cQuote As String = """") As Boolean
IsStringifiableQuery = False
If (Left$(strQuery, 1) = cQuote) Then GoTo Common_Exit
Dim oTokens As Tokenizer: Set oTokens = New Tokenizer
oTokens.Init strQuery
Dim strToken As String
Dim lNumTerms As Long: lNumTerms = 0
Do While (Not oTokens.eof)
DoEvents
strToken = oTokens.NextWord
lNumTerms = lNumTerms + 1
If (bIsOpNot(strToken) Or _
bIsOpOr(strToken) Or _
bIsOpAnd(strToken) Or _
"(" = Left$(strToken, 1) Or ")" = Left$(strToken, 1)) Then
GoTo Common_Exit
End If
Loop
If (lNumTerms = 1) Then GoTo Common_Exit
IsStringifiableQuery = True
Common_Exit:
Exit Function
End Function
Private Function bIsOpNot(strToken As String) As Boolean
bIsOpNot = False
If (strToken = "not") Then bIsOpNot = True: GoTo Common_Exit
If (strToken = "!") Then bIsOpNot = True: GoTo Common_Exit
Common_Exit:
Exit Function
End Function
Private Function bIsOpOr(strToken As String) As Boolean
bIsOpOr = False
If (strToken = "or") Then bIsOpOr = True: GoTo Common_Exit
If (strToken = "||") Then bIsOpOr = True: GoTo Common_Exit
Common_Exit:
Exit Function
End Function
Private Function bIsOpAnd(strToken As String) As Boolean
bIsOpAnd = False
If (strToken = "and") Then bIsOpAnd = True: GoTo Common_Exit
If (strToken = "+") Then bIsOpAnd = True: GoTo Common_Exit
If (strToken = "&") Then bIsOpAnd = True: GoTo Common_Exit
Common_Exit:
Exit Function
End Function
Private Function IsStopWord(strWord As String) As Boolean
IsStopWord = False
If (m_oDocStw Is Nothing) Then GoTo Common_Exit
Dim cQuote As String
If (InStr(strWord, "'") > 0) Then
cQuote = """"
Else
cQuote = "'"
End If
IsStopWord = (Not m_oDocStw.selectSingleNode("//STOPWORD[@STOPWORD = " + cQuote + LCase$(strWord) + cQuote + "]") Is Nothing)
Common_Exit:
Exit Function
End Function
Sub GetRidOfStopSignsAndMultipleWhiteSpaces( _
ByRef strQuery As String, _
ByRef out_dictStopSigns As Scripting.Dictionary _
) ' As String
If (Not out_dictStopSigns Is Nothing) Then
out_dictStopSigns.RemoveAll
Else
Set out_dictStopSigns = New Scripting.Dictionary
End If
Dim i As Long, cSS As String
For i = Len(strQuery) To 1 Step -1
If (bIsStopSign(strQuery, i)) Then
cSS = Mid$(strQuery, i, 1)
strQuery = Left$(strQuery, i - 1) + " " + Mid$(strQuery, i + 1)
If (Not out_dictStopSigns.Exists(cSS)) Then
out_dictStopSigns.Add cSS, cSS
End If
End If
Next i
' GetRidOfStopSignsAndMultipleWhiteSpaces = strQuery
End Sub
Function bIsStopSign(strWList As String, i As Long) As Boolean
' Dim strErrMsg As String: strErrMsg = "": If (g_bOnErrorHandling) Then On Error GoTo Error_Handler
bIsStopSign = False
If (i > Len(strWList)) Then GoTo Common_Exit
Dim strStopSign As String: strStopSign = Mid$(strWList, i, 1)
If (m_odictStopSigns.Exists(strStopSign)) Then
Select Case m_odictStopSigns.Item(strStopSign)
Case STOPSIGN_AT_END_OF_WORD
' We check whether the stop sign follows a space or any other character.
If (i = 1) Then
bIsStopSign = False
Else
Dim strPreviousSign As String: strPreviousSign = Mid$(strWList, i - 1, 1)
Select Case strPreviousSign
Case " ", vbTab
bIsStopSign = False
Case Else
If (i = Len(strWList)) Then
' If it is the last character in string, then it is a stop sign.
bIsStopSign = True
Else
' In order to definitely establish that his stopword is at the
' end of a word, we need to look at the next character
Dim strNextSign As String: strNextSign = Mid$(strWList, i + 1, 1)
Select Case strNextSign
Case " ", vbTab, """"
bIsStopSign = True
Case Else
bIsStopSign = False
End Select ' strNextSign
End If
End Select ' strPreviousSign
End If ' ( i = 1 )
Case Else
' This is a non-context sensitive Stopsign, so simple existence in the
' Stop Sign Dictionary means that it is indeed a stop sign
bIsStopSign = True
End Select
Else
' It does not exist on the StopSign Map, so let's get out of here.
bIsStopSign = False
End If ' (m_odictStopSigns.Exists(strStopSign))
Common_Exit:
Exit Function
Error_Handler:
' g_XErr.SetInfo "bIsStopSign", strErrMsg
' Err.Raise Err.Number
End Function
'Function StopSign2WhiteSpace( _
' ByRef strQuery, _
' ByVal i As Long _
' ) As Boolean
'
'
' Const STOP_SIGN_AS_END_OF_WORD As Long = 3
' Const STOP_SIGN_ANYWHERE As Long = 0
'
' Dim cSS As String: cSS = Mid$(strQuery, i, 1)
' Dim bIsStopsign As Boolean: bIsStopsign = False
' If (m_StopSignMap.Exists(cSS)) Then
'
' Select Case m_StopSignMap.Item(cSS)
' Case STOPSIGN_AT_END_OF_WORD
'
' If (i = 1) Then
' If we are at the beginning of a word, by definition we are NOT at the end of a word,
' bIsStopsign = False
' Else
' Dim strPreviousSign As String: strPreviousSign = Mid$(strWord, i - 1, 1)
'
' Select Case strPreviousSign
' Case " ", vbTab
' bIsStopsign = False
' Case Else
' If (i = Len(strWord)) Then
' If it is the last character in string, then it is a stop sign.
' bIsStopsign = True
' Else
' In order to definitely establish that his stopword is at the
' end of a word, we need to look at the next character
' Dim strNextSign As String: strNextSign = Mid$(strWord, i + 1, 1)
' Select Case strNextSign
' Case " ", vbTab
' bIsStopsign = True
' Case Else
' bIsStopsign = False
' End Select ' strNextSign
' End If
'
' End Select ' strPreviousSign
' End If ' ( i = 1 )
'
' Case Else
' This is a non-context sensitive Stopsign, so simple existence in the
' Stop Sign Dictionary means that it is indeed a stop sign
' bIsStopsign = True
' End Select
'
' Else
' It does not exist on the StopSign Map, so let's get out of here.
' bIsStopsign = False
'
' End If ' (m_odictStopSigns.Exists(strStopSign))
'
'Common_Exit:
' If (bIsStopsign) Then
' strQuery = Left$(strQuery, i - 1) + " " + Mid$(strQuery, i + 1)
' End If
'
' Exit Function
'
'Error_Handler:
'
'End Function
' This function HAS to be called by bContainsStopSigns, as it is impossible for it to detect
' Runs of alternate context dependente and context independent Stopsigns.
'inline static void GetRidOfStopSignsAndMultipleWhiteSpaces( WCHAR *& szStr )
'{
' WCHAR *psz = szStr ;
' for ( ; *psz ; ++ psz ) ;
' for (; psz >= szStr; -- psz )
' {
' StopSign2WhiteSpace( szStr, psz ) ;
' }
'
' int iWspCount = 0;
' WCHAR *psz2 = psz ;
' for ( ; *psz ; ++ psz )
' {
' if ( iswspace( *psz ) )
' {
' ++ iWspCount ;
' if ( iWspCount > 1 )
' {
' continue ;
' }
' }
' Else
' {
' iWspCount = 0 ;
' }
' *psz2 = *psz ;
' ++ psz2 ;
' }
' *psz2 = 0 ;
'}
' This function HAS to be called by bContainsStopSigns, as it is impossible for it to detect
' Runs of alternate context dependente and context independent Stopsigns.