三、调查表单的生成与结果分析
作 者 : 仙人掌工作室
PollWriter.asp先检查表单变量,包括调查项目名字PollName以及(可选的)字符串LinkText和LinkURL,LinkText和LinkURL描述了用户提交其投票结果之后显示的URL。接下来脚本创建并执行从指定调查项目的S_表和A_表提取记录集的SQL命令,然后遍历这个记录集格式化单选按钮、复选框以及其它提示文本,最后输出该调查项目的HTML表单。表单中问题的名字为“CHOICE”加问题序号。当这个表单被提交的时,它的ACTION将装载PollMaker.asp(这里的函数saveResponses()从CHOICE表单元素提取投票结果,然后更新数据库,代码略)。表单中的其它隐藏变量用于将PollName、OpType、LinkText、LinkURL传递给PollMaker.asp:
< %
' 从S_表和A_表读取调查项目定义
Set objConn = Server.CreateObject("ADODB.Connection")
objConn.Open "poll"
SQLCommand = "Select " & SName & ".ID, " & _
"IType, NoOpinion, Stem, ALabel, Answer FROM " & SName & "LEFT JOIN " & _
AName & " ON " & SName & ".ID = " & AName & ".ID ORDER BY " & _
SName & ".ID, ALabel"
Set objRS = objConn.Execute(SQLCommand)
' 向调查表单输出各个问题
Do While Not objRS.EOF
Response.Write("< TR>< TD>" & objRS("ID") & ".< TD BGCOLOR=""#ffff00"">" & _
objRS("Stem"))
Response.Write("< TR>< TD>< TD>")
ckNoOpinion = IIf(objRS("NoOpinion") = "Y", "", "Checked")
noMove = False
' 除"允许复选",其它各类问题均需检查是否允许不回答问题
ansName = """CHOICE" & objRS("ID") & """"
Select Case objRS("IType")
Case "1" ' 是/否
If ckNoOpinion = "" Then
Response.Write(" < INPUT TYPE=radio NAME=" & ansName & _
" VALUE="" "" Checked>暂不回答 ")
End If
Response.Write("< INPUT TYPE=radio NAME=" & ansName & _
" VALUE=""A"" " & ckNoOpinion & ">是")
Response.Write("< INPUT TYPE=radio NAME=" & ansName & _
" VALUE=""B"">否")
Case "2" ' 赞同程度
...略...
Case "3" ' 语义区分
...略...
Case "4" ' 多项选择
...略...
Case "5" ' 允许复选
...略...
End Select
If NoMove Then
NoMove = False
ElseIf Not objRS.EOF Then
objRS.MoveNext
End If
Loop
%>
PollResult.asp使用与PollWrite.asp同样的SQL命令从A_表(答案)和S_表(问题)提取记录集,接着从对应的R_表读取用户回答结果,用一个二维数组Counts统计投票结果。缺省时结果分析中不包含“没有回答”,如果要包含,则需给出表单变量ShowNoOp并指定其值为True,请参见图4中显示投票结果的URL。
< %
'Globals
Dim PollName
Dim Counts() ' 用户回答的统计数组
Dim nResponses
Dim N ' 用户回答数量,可能不包含"没有回答"选项
Dim objConn
Dim objRS
nResponses = 0
Call Main
Sub Main
Dim likert
Dim i
Likert = Array("强烈反对","反对", "不确定","同意","完全赞成")
PollName = Request("PollName")
ShowNoOp = IIf(UCase(Request("ShowNoOp"))="TRUE", True, False)
' 从A_表和S_表读取调查项目定义
Set objConn = Server.CreateObject("ADODB.Connection")
objConn.Open "poll"
SName = "[S_" & PollName & "]"
AName = "[A_" & PollName & "]"
If Count() = False Then
Response.Write("< BR>此调查项目没有投票结果")
Exit Sub
End If
SQLCommand = "Select " & SName & ".ID, " & _
"IType, NoOpinion, Stem, ALabel, Answer FROM " & SName & _
"LEFT JOIN " & AName & " ON " & SName & ".ID = " & AName & _
".ID ORDER BY " & SName & ".ID, ALabel"
Set objRS = objConn.Execute(SQLCommand)
Response.Write("< TABLE>")
... 输出表单标题,略 ...
Response.Write("< TR>< TD COLSPAN=5> ")
itemIx = 0 ' 问题序号
Do While Not objRS.EOF
IType = objRS("IType")
NoMove = False
N = IIf(ShowNoOp Or IType=5, nResponses, nResponses-Counts(itemIx, 0))
N = IIf(N=0, 1, N)
Response.Write("< TR>< TH ALIGN=right>" & objRS("ID") & _
".< TH ALIGN=left COLSPAN=4 BGCOLOR=""#ffff00"">" & objRS("Stem"))
Response.Write("< TR>< TD>" & _
"< TD ALIGN=center WIDTH=300 BGCOLOR=""#ffff00"">回答" & _
"< TD ALIGN=right BGCOLOR=""#ffff00"">N" & _
"< TD ALIGN=right BGCOLOR=""#ffff00"">%" & _
"< TD WIDTH=200 BGCOLOR=""#ffff00""> ")
If ShowNoOp And objRS("NoOpinion") = "Y" And IType < > "5" Then
Call writeResponse("没有回答", itemIx, 0, "#ff0000")
End If
Select Case IType
Case "1" '是/否
Call writeResponse("是", itemIx, 1, "#00ff00")
Call writeResponse("否", itemIx, 2, "#00ff00")
Case "2" '赞同程度
...略...
Case "3" '语义区别
...略...
Case "4" '多项选择
...略...
Case "5" ' 允许复选
...略...
End Select
Response.Write("< TR>< TD>< TD ALIGN=right>总回答次数: " & _
"< TD ALIGN=right>" & N & "< TD>< TD>")
Response.Write("< TR>< TD COLSPAN=5> ")
If NoMove Then
NoMove = False
ElseIf Not objRS.EOF Then
objRS.MoveNext
End If
itemIx = itemIx + 1
Loop
Response.Write("< /TABLE>")
End Sub 'Main
' 统计投票次数
Function Count()
Dim i, j
RName = "[R_" & PollName & "]"
Set objRS = objConn.Execute("SELECT Responses FROM " & RName)
If objRS.BOF Then '没有投票记录
Exit Function
End If
nAnswers = Len(objRS("Responses")) ' 投票结果字符串的字符数
ReDim Counts(nAnswers-1, 26) ' 允许 ' '+ A 到 Z
For i = 0 To nAnswers-1 ' 初始化统计数组
For j = 0 To 26
Counts(i, j) = 0
Next
Next
nResponses = 0
Do While Not objRS.EOF
Responses = objRS("Responses")
nResponses = nResponses + 1
nAnsThis = Len(Responses) ' 当前回答字符串中的字符数
If nAnsThis < > nAnswers Then
Count = False
Exit Function
End If
For i = 0 To nAnsThis-1 ' 统计各个问题的投票数
respLtr = Mid(Responses, i+1, 1)
If respLtr = " " Then
Counts(i,0) = Counts(i,0) + 1
Else
respIx = Asc(respLtr) - 64 ' 将字母转换为索引值
If respIx > 0 And respIx < 27 Then
Counts(i,respIx) = Counts(i,respIx) + 1
End If
End If
Next
objRS.MoveNext
Loop
objRS.Close
Count = True
End Function 'Count()
'输出一个表格行
Sub writeResponse(respStr, itemIx, ansIx, barColor)
Response.Write("< TR>< TD>< TD>" & respStr & _
"< TD ALIGN=right>" & Counts(itemIx, ansIx) & "< TD ALIGN=right>" & _
FormatNumber(100*Counts(itemIx, ansIx)/N, 1) & "< TD>")
Call writeBar(Counts(itemIx, ansIx)/N, barColor)
End Sub 'writeResponse()
' 用嵌套表格的背景色显示统计直方图
Sub writeBar(percent, barColor)
Response.Write("< TABLE CELLSPACING=0 CELLPADDING=0 WIDTH=""" & _
200*percent & """>< TR>< TD BGCOLOR=""" & barColor & """>" & _
IIf(percent>0, " ", "") & "< /TD>< /TABLE>")
End Sub 'writeBar()
...其它辅助函数,略...
%>
四、其它说明
⑴ 示例代码假定ASP脚本放在服务器的/Scripts目录下。如果放到了另外一个目录下,则需修改Startup.html中PollMaker.asp文件的路径。所有的ASP文件必须在同一目录下。
⑵ 示例代码中的Poll.mdb是一个ACCESS数据库,应该为它创建一个ODBC名字,即用Windows控制面板中的“32位ODBC数据源”为该数据库创建名为“POLL”的系统DSN。整个系统只需一个数据库即可,这和调查项目的多少无关。
⑶ 支持ItemMaker.asp编辑操作的JavaScript函数位于最上面的帧ControlFrame,但有时候被中间帧ItemFrame中的事件调用。因此,这些函数的引用必须包含文档模型的层次关系,如:parent.ControlFrame.saveItem()。如果不是通过Startup.html,而是直接打开ItemMaker.asp,由于帧结构不存在会出现JavaScript错误。
⑷ 在本实现中,当投票结果保存到R_表之后仍旧允许修改调查项目定义。这使得调查项目启用之后还可以改正提示文本上的问题,但也带来潜在的问题,即当问题被创建、删除或改变次序之后,它与已有的投票结果之间可能出现错误的对应关系。因此,对于已有投票结果的调查项目,执行上述操作之前应该使用图1中的“删除调查结果”按钮删除已有结果。
⑸ 从其它地方引用调查表单(PollWriter.asp)或结果分析页面(PollResult.asp)时,必须提供它们所要用到的表单变量(如PollName、ShowNoOp、LinkText、LinkURL)。打开调查表单的完整URL格式为:
http://ygroup01/scripts/PollWriter.asp?PollName=Test+Poll+1&LinkText=Return+to+Home+Page&LinkURL=/
打开调查结果分析页面的完整URL格式为:
http://ygroup01/Scripts/PollResult.asp?PollName=Test+poll+1&ShowNoOp=True
⑹ 本文只提供了5种问题类型,在实际应用场合可能需要定义其它的问题类型。在已有的框架内增加新的问题类型需要扩展(修改)ItemMaker.asp、PollWriter.asp、PollResult.asp这三个文件。
⑺ 如果要对投票结果作更为复杂的分析,可以使用那些支持从Access导入数据的标准统计软件包,也可以先将Access数据库导出为文本格式,然后再导入到其它软件。