article

ASP and XML Surveys

Email
Submitted on: 1/5/2015 6:20:00 PM
By: George Leithead (from psc cd)  
Level: Intermediate
User Rating: By 7 Users
Compatibility: ASP (Active Server Pages), HTML, VbScript (browser/client side)
Views: 974
 
     Ever wanted a survey on your site? But don't have a database? Well, by using ASP and XML you can! Features single voting, survey expiry, past survey results, and many nore...

 
						You've seen them all over the web. They've popped up more and more. What am I talking about? I'll tell you wat I'm talking about, surveys and user poll's, thats what. Well, I have some code here that will allow you to implement a survey all without a database and other expensive components.

All code mentioned in this article can be downloaded from here, can can be discussed here

What do we need from a survey? Well, simply we need a question, answers to the question, and the ability to record the number of votes. This is acheived with the following simply XML structure:
<survey voters="1">
    <id />
    <question />
    <answer votes="1" />
    <dateend />
</survey>

Breaking this down, we can see that we have a survey node. We can have as many survey nodes as we like. This survey node has one attribute, voters. This will be used to record the number of votes taken for this survey. Each survey, has an ID, question and answer element(s). The id is used to uniquley identify each survey. Each survey has a question, and each survey can have one or more answers. After all a question with only one answer would be prity pointless. The last element is date end. This is used to specify when the survey is to end.

You'll also notice that the answer element has a votes attribute. This will be used to record the number of votes for the selected answer.

An exam of a populated survey might be:
<survey voters="1">
<id />1</id>
<question>Do you think surveys are a good idea?</question>
<answer votes="0">Great</answer>
<answer votes="1">Not Bad</answer>
<answer votes="0">Average</answer>
<answer votes="0">Poor</answer>
<answer votes="0">Rubbish!</answer>
<dateend>20011231</dateend>
</survey>

Now that we have defined the information we need, next we need to define a way to display it. By using XSL this is made relativley simple:
<render id="vradio">
    <FORM ACTION="Poll.asp" TARGET="Poll" METHOD="POST" onSubmit="window.open('','Poll','width=300,height=120,toolbar=no,location=no,directories=no,status=no,menubar=no,resizable=no,scrollbars=no');">
    <INPUT TYPE="HIDDEN" NAME="ID">
        <xsl:attribute name="VALUE"><xsl:value-of select="id"/></xsl:attribute>
    </INPUT>
    <TABLE BORDER="1" CELLPADDING="0" CELLSPACING="0" WIDTH="280" SUMMARY="Survey">
    <TR>
        <TH>Survey</TH>
    </TR>
    <TR>
        <TD ALIGN="center">
            <TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0" WIDTH="100%" HEIGHT="100%" SUMMARY="Survey Question and Answers">
            <TR>
                <TH COLSPAN="2"><xsl:value-of select="question"/></TH>
            </TR>
            <xsl:for-each select="answer">
            <TR>
                <TD ><xsl:value-of /></TD>
                <TD ><INPUT TYPE="radio" NAME="Poll">
                        <xsl:attribute name="value"><xsl:value-of/></xsl:attribute>
                    </INPUT>
                </TD>
            </TR>
            </xsl:for-each>
            <TR>
                <TD ALIGN="right" COLSPAN="2"><INPUT TYPE="submit" NAME="Submit" VALUE="Vote" /></TD>
            </TR>
            </TABLE>
        </TD>
    </TR>
    </TABLE>
    </FORM>
</render>

<render id="results">
    <TABLE BORDER="1" CELLPADDING="0" CELLSPACING="0" WIDTH="280" SUMMARY="Survey Results">
    <TR>
        <TH>Survey Result</TH>
    </TR>
    <TR>
        <TD ALIGN="center">
            <TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0" WIDTH="100%" HEIGHT="100%" SUMMARY="Survey Result">
            <TR>
                <TH COLSPAN="3"><xsl:value-of select="question"/></TH>
            </TR>
            <TR>
                <TD COLSPAN="3" ALIGN="CENTER">Total Voters: <xsl:value-of select="@voters"/></TD>
            </TR>
            <xsl:for-each select="answer">
            <TR>
                <TD ALIGN="RIGHT">
                    <IMG SRC="Images/Vote.gif" HEIGHT="10" ALT="Votes">
                    <xsl:attribute name="WIDTH"><xsl:eval>Math.round(this.getAttribute("votes")/this.parentNode.getAttribute("voters") * 100)</xsl:eval></xsl:attribute>
                    </IMG>
                </TD>
                <TD ALIGN="RIGHT">
                    <xsl:eval>Math.round(this.getAttribute("votes")/this.parentNode.getAttribute("voters") * 100)</xsl:eval>%
                </TD>
                <TD WIDTH="100%"><xsl:value-of/></TD>
            </TR>
            </xsl:for-each>
            </TABLE>
        </TD>
    </TR>
    <TR>
        <TD ALIGN="center"><A HREF="ViewPastPolls.asp">View Results of past surveys</A><IMG SRC="http://forums/internetwideworld.com/Images/Blank.gif" height="0" width="0" alt="Weaval" /></TD>
    </TR>
    </TABLE>
</render>
Now we have our information, and a template to display it in, we now need to select the correct survey for display. Firstly, we need to load the XML and XSL files:
Application("SurveyPath")= server.MapPath("src/") & "\" ' NEED to add on the extra Application("SurveySource") = server.MapPath("src/surveys.xml")
Application("SurveyStyle") = server.MapPath("src/surveys.xsl")
Function loadSurveys() 
 Dim source, style, rootPath
 rootPath = Application("SurveyPath")
 set source = Server.CreateObject("Microsoft.FreeThreadedXMLDOM")
 source.async = false
 source.load Application("SurveySource")
 set style = Server.CreateObject("Microsoft.FreeThreadedXMLDOM")
 style.async = false
 style.load Application("SurveyStyle")
 application.lock
 set application("survey") = source
 set application("style") = style
 application.unlock
end Function
Next we need to actually display the survey. This is acheived by selecting the first survey where the dateend is greater than today, we can select the correct survey.
Function GetDate()
	'Produces YYYYMMDD
	DIM dYear : dYear = Year(Now())
	DIM dMonth : dMonth = Month(Now())
	DIM dDay: dDay = Day(Now())
	DIM iID: iID = 1
	DIM iLoop : iLoop = 1
	If Len(dMonth) < 2 then dMonth = "0" & dMonth
	If Len(dDay) < 2 then dDay = "0" & dDay
	
	GetDate = dYear & dMonth & dDay
End Function
Function DisplayLatestSurvey()
	DIM oRequiredNode
	DIM oSource
	DIM oStyle
	DIM oOutNode
	DIM sRender : sRender = "vradio"
	DIM iID: iID = 1
	DIM dDate : dDate = GetDate()
	set oSource = Application("survey")
	set oStyle = Application("style")
	set oRequiredNode = oSource.selectSingleNode("surveylist/survey[dateend[. > """ & dDate & """]]")
	if NOT oRequiredNode is nothing then
		iID = oRequiredNode.selectSingleNode("id").text ' Get the Survey ID!
		If InStr(Request.Cookies("Survey"),":" & iID & ":") > 0 then
			sRender = "results"
		End If
		set oOutNode = oStyle.selectSingleNode("xsl:stylesheet/render[@id=""" & sRender & """]")
		if NOT oOutNode is nothing then
			' Apply the style to the source!
			DisplayLatestSurvey = oRequiredNode.transformNode(oOutNode)
		else
			DisplayLatestSurvey = "ERROR: Either the XSL file is incorrect or the render identifier is not found"
		end if
	else
		DisplayLatestSurvey = "ERROR: Either no survey exists for this period or the survey was not found"
	end if
	' Tidy Up!!!
	set oOutNode = nothing
	set oRequiredNode = nothing
	set oStyle = nothing
	set oSource = nothing
End Function
Within the DisplayLatestSurvey function there are two items to pay particular attention to. Firstly, sRender = "vradio" specifies the render style we want, which is contained within the XSL file.
The second item of note, is the Request.Cookies. Obviously, if some one has already voted in the survey, we don't want them to vote again. So, we determine if the user has a cookie this survey. If they do not, simply display the vradio XSL display. Oterhwise, they have already voted, and we change the XSL render to be results. This XSL render displays the actual voting for the survey.
So far, we've only displayed the survey and the survey results. But what about letting the user register their vote? This is by adding 1 to not only the number of voters, but also by adding 1 to the number of votes for an answer.
function voteSurvey(ByVal sID, ByVal sVote, ByRef bResult)
 Dim findNode, result, rootPath, source
 if sVote<>"" then
set source = application("survey")
set findNode = source.selectSingleNode("surveylist/survey[id[. = """ & sID & """]]/answer[.=""" & sVote & """]")
if not findNode is nothing then
	findNode.setAttribute "votes", findNode.getAttribute("votes") + 1
	set findNode = findNode.parentNode
	findNode.setAttribute "voters", findNode.getAttribute("voters") + 1
		 rootPath = Application("SurveyPath")
	saveSurveys source
	bResult = true
	result = "Your vote has been accepted!"
else
	 result="Your vote choice for this poll is invalid!"
end if
 end if
 voteSurvey = result
 if bResult then CALL SetSurveyCookie(sID)
end function
function saveSurveys(obj) 
 Dim rootPath,s
 rootPath = Application("SurveyPath")
 obj.save rootPath & "surveys.xml"
 for each s in application.contents
	if left(s,6)="SURVEY" and s<>"SURVEY" then
		application.lock
		set application(s) = nothing
		application.unlock
	end if
 next
end function
Function SetSurveyCookie(ByVal iID)
	Response.Cookies("Survey") = ":" & iID & ":"
	Response.Cookies("Survey").Expires = "January 1, 2011"
End Function
Once we register the vote, we need to then save the results, and 'unload' the previous version of the XML file, so that the new results can be viewed.
Then in order to prevent the user from re-submitting another vote, we send the user a cookie with the survey id that they voted in.

As additional functionality, we may also want to display a list of 'past' surveys and their results. This is acheived by implementing a new XSL render template, and some more ASP code. These and more can be found in the downloadable code, from here.

To discuss this article and the code go here.Weaval


Report Bad Submission
Use this form to tell us if this entry should be deleted (i.e contains no code, is a virus, etc.).
This submission should be removed because:

Your Vote

What do you think of this article (in the Intermediate category)?
(The article with your highest vote will win this month's coding contest!)
Excellent  Good  Average  Below Average  Poor (See voting log ...)
 

Other User Comments


 There are no comments on this submission.
 

Add Your Feedback
Your feedback will be posted below and an email sent to the author. Please remember that the author was kind enough to share this with you, so any criticisms must be stated politely, or they will be deleted. (For feedback not related to this particular article, please click here instead.)
 

To post feedback, first please login.