Programmer to ProgrammerTM | |||||
|
|
|
|
|
|
|
|
|
|
|
| |||||||||||||||||||
The ASPToday
Article October 17, 2001 |
Previous
article - October 16, 2001 |
||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||
ABSTRACT |
| ||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||
Article Discussion | Rate this article | Related Links | Index Entries | ||||||||
ARTICLE |
It's the intent of software to make you work smarter, not harder.
One of the biggest challenges that traditional companies face when starting to embrace the online revolution is the publishing aspect of getting their content online (which for them, being newbies, can be a monstrosity of a challenge). Traditional Web authoring mandated that a content author would have to know the intricacies of HTML - which largely ruled out any staffers except for progressive MIS programmers or a few daring advertising and creative people - and also be savvy enough to know how to get their content online.
As the Web continued to mature, more people began to pick up how to create HTML documents, but simultaneously Web access became available from beyond the confines of the normative PC (mobile devices, Internet appliances, etc.) making publishing quite complex in terms of the creation and management of content. Controlling such a system is beyond the normal capacity of most organizations today.
Since I currently manage a Web site for which local news information is the prime attraction, it's important to me to be able to let our content producers easily get their work up online - quickly - without forcing them to actually write complex code (which they shouldn't have to do), and without me having to do the work for them (which I shouldn't have to do). Its part of our responsibility as developers to design and then deploy our applications, and then move on to the next thing.and not become slaves to them, doing manual data entry and updating.
In this lesson, we're going to build a very simple document management system, which anyone in the office can use, thus freeing up your Web staff to work on other projects. We'll be using XML documents to hold our core data - in this case, news articles - in combination with scripting within Active Server Pages to present the content nicely. I use a system not unlike the one we're about to create for running some aspects of our newsroom; you might use it for company newsletters, product examples, or your personal listing of your favorite episodes of "The Transformers". It's completely adaptable.
When I was mapping our site and features early on, I theorized that to really be a superior competitor we would have to have our information available in a variety of formats (HTML for our public site on the World Wide Web, on mobile devices such as Palm Pilots, PocketPCs, on advanced mobile phones through WAP, on alphanumeric pagers, through push channels using RSS, and so on). I envisioned us having to have our data centralized and single-sourced, so as not to force an author to write one story six separate times, in six different formats.
It was also an interest of mine, as a marketing tactic, to develop a syndication service for our content and have our news content portable, so that our headlines could be implemented easily on other sites external to ours. I was also interested in getting our articles recognized by the major search engines like Google and Excite, as well as by search directories such as Yahoo and Snap.
Database-driven sites that generate querystring-based URLs (i.e., http://www.domain.com/filename.asp?id=8675309) aren't always crawled by search engine and search directory spiders and this results in pages not being indexed with the Web's major search services, which is a negative factor in getting your site recognized and marketed. Thus, I wanted to create a system that would output our stories in individual files that search services would be able to crawl and list more effectively.
OK, so it's not as dramatic as selecting pistols at dawn, but it's important to know the capabilities and limitations of the technologies your application is based upon. I chose XML as the fundamental data technology because of its universality, and the fact that we can take a single document and have it ported to different platforms (our public Web site, our mobile channels, our portable headlines) through the use of a number of written XSL stylesheets (eXtensible Stylesheet Language). The management of the various formats for the document is simple.
I use ASP as the presentation platform because it supports a very simple script construct that lets us display the data in an XML document, according to formatting defined in an XSL stylesheet:
<% ' Load the XML document Set source = Server.CreateObject("Microsoft.XMLDOM") source.async = false source.load(Server.MapPath("an XML filename")) ' Load the XSL stylesheet Set style = Server.CreateObject("Microsoft.XMLDOM") style.async = false style.load(Server.MapPath("an XSL stylesheet")) ' Write out the page contents Response.Write(source.transformNode(style)) ' Destroy all object references Set source = Nothing Set style = Nothing %>
The script instantiates the Microsoft XML Document Object Model (MSXML DOM) twice, once for the XML document containing our story data, and once for the XSL stylesheet we're going to apply to it. The end result will be a file with the extension of .ASP , with the data in the XML document presented as HTML.
What this system makes possible is multi-platform publishing. Remember here that they key to make this app work is to make the core asset - the data - the key ingredient, and not limiting ourselves to a single method of presenting that data and likewise not imposing on ourselves the monstrous task of creating separate pages for multiple platforms (in my example, our public Web site, mobile device channel, push channel and external portable service). This makes expansion easier.
If we choose, we can also make this data available to be ported to other partners, who in my situation might be network news providers or local affiliates. They can take the core data in the XML documents and write their own formatting schemes using XSL's transformation language (XSLT) to have the XML data work according to their own system's specifications, and then apply XSL's formatting objects (XSLFO) to have it match their own color schemes and layout etc.
The way this system works is by:
Presenting the user with a simple Web form that they enter the appropriate data into
Passing the data through a processing script that will create an XML document on the fly and save it to the Web server, with customized tags that we'll define (and can easily modify)
Confirming the creation of the XML file and persisting filename information from the XML file to dynamically create an ASP file corresponding to the saved XML document
Creating an ASP Page and saving it to the Web server that will be presented as formatted HTML when viewed in the client's browser. Also check for the existence of errors, to ensure that files with the same name are not written to the Web server's disk, halting execution of the program, and reporting any found errors to the user without catastrophically crashing the program.
Applying formatting to each that we'll define in a series of XSL stylesheets to present our stories nicely in a variety of digital formats (Web, mobile devices, push)
Firstly, make sure whichever Web server is hosting your application can support ASP 2.0 or higher. To follow the structure of this example, you should also create a subdirectory on your Web server and name it " xmlnews ", and an additional subdirectory within xmlnews called " images " (to contain all your graphics), such that the paths are as follows:
c:\inetpub\wwwroot\xmlnews\
c:\inetpub\wwwroot\xmlnews\images
Upload or save the images included in the Zip file containing the source code to the images directory. If your Web server is set up differently, you'll just need to change a couple of paths to reflect your own server's directory structure.
Note: this application is based on the default server path mapped by Microsoft Internet Information Server versions 4 and 5, as well as Microsoft Personal Web Server. If you are using a different Web server, or have modified your settings so that the path specified in the scripts is different, you'll need only to modify the server path referenced in CREATE-XML-DOC.ASP and NEW_STORY_TEMPLATE.ASP.
As in any good dynamic Web application, it's best to draw out exactly how we want the end result of our application's work to look. Since we're using XML, we get to define the tags ourselves that will make up our data document. Before being populated with data, the XML document should have the following structure:
<STORIES> <STORY> <DATE></DATE> <TITLE></TITLE> <SUBHEAD></SUBHEAD> <REPORTER></REPORTER> <REPORTERGRAPHIC></REPORTERGRAPHIC> <MAILTO></MAILTO> <BODY> <P1></P1> <P2></P2> <P3></P3> <P4></P4> <P5></P5> <P6></P6> <P7></P7> <P8></P8> <P9></P9> <P10></P10> </BODY> <GRAPHIC></GRAPHIC> <QUOTE></QUOTE> <QUOTEDPERSON></QUOTEDPERSON> <QUOTEDPERSONTITLE></QUOTEDPERSONTITLE> </STORY> </STORIES>
These are all the elements that I use to populate our stories. If an element is left blank when a user enters information in the Web form, nothing is displayed in the resultant page. If a reporter has no significant quote from someone they interviewed, they just leave this field blank and it doesn't hurt the page.
The nodes DATE , TITLE , SUBHEAD , REPORTER , REPORTERGRAPHIC , MAILTO , BODY , GRAPHIC , QUOTE , QUOTEDPERSON , and QUOTEDPERSONTITLE are direct descendants of the STORY node, which itself falls under the document element STORIES . Since most of our stories are ten paragraphs or less I've written ten child nodes ( P1 , P3 ... P10 ) of the BODY node, which will make up the textual body of the story. Each XML document will contain only a single STORY node, so you have only one story per file.
We then examine the HTML behind it and determine a way in which we can create script code to dynamically perform the work for us. Once this architecture (the look) and the method (the means of programmatically creating the system to carry out the work) are in place, we can build our app.
Now that we have our data elements (the XML STORY nodes), we build a template using XSL to generate the desired layout with HTML formatting (i.e., functional hyperlinks and inserting an image within the story). Remember that the script that will fire in each ASP page will reference and load this file for styling via the XML Document Object Model (DOM), so this means that if management one day decided to go in a different direction, or we did a redesign of the site, we would need to modify NEWS-ARTICLE.XSL only, and all stories would automatically be retrofitted to reflect this change.
Here's the code for NEWS-ARTICLE.XSL :
<?xml version='1.0'?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl"> <xsl:template match="/"> <xsl:for-each select="STORIES/STORY" order-by="DATE"> <HTML> <HEAD> <TITLE> <xsl:value-of select="TITLE"/> </TITLE> </HEAD> <BODY bgcolor="#FFFFFF"> <P> <font face="verdana" size="5" color="teal"> <b><xsl:value-of select="TITLE"/></b> </font> <br/> <font face="verdana" size="2" color="teal"> <b>by <a><xsl:attribute name="href"><xsl:value-of select="MAILTO"/> </xsl:attribute> <xsl:value-of select="REPORTER"/></a>, <xsl:value-of select="DATE"/> </b> </font> <br/> <br/> <font face="verdana" size="3" color="red"> <b><xsl:value-of select="SUBHEAD"/></b> </font> </P> <BLOCKQUOTE> <TABLE cellpadding="2" cellspacing="1" width="87%"> <tr> <td align="left" width="50%"> <img> <xsl:attribute name="src"> <xsl:value-of select="REPORTERGRAPHIC"/> </xsl:attribute> </img> </td> <td align="right" valign="top"> <font face="Arial" color="red" size="3"> <b><xsl:value-of select="QUOTE"/></b> </font> <br/> <font face="Arial" color="black" size="2"> <b><xsl:value-of select="QUOTEDPERSON"/></b> </font> <br/> <font face="arial" color="black" size="1"> <b><xsl:value-of select="QUOTEDPERSONTITLE"/></b> </font> </td> </tr> </TABLE> <font face="verdana" size="2" color="black"> <P align="justify"> <img align="right" hspace="30"> <xsl:attribute name="src"> <xsl:value-of select="GRAPHIC"/> </xsl:attribute> </img> <font size="3"><b><xsl:value-of select="BODY/P1"/></b></font><br/><br/> <font size="2"> <P align="justify"><xsl:value-of select="BODY/P2"/></P> <P align="justify"><xsl:value-of select="BODY/P3"/></P> <P align="justify"><xsl:value-of select="BODY/P4"/></P> <P align="justify"><xsl:value-of select="BODY/P5"/></P> <P align="justify"><xsl:value-of select="BODY/P6"/></P> <P align="justify"><xsl:value-of select="BODY/P7"/></P> <P align="justify"><xsl:value-of select="BODY/P8"/></P> <P align="justify"><xsl:value-of select="BODY/P9"/></P> <P align="justify"><xsl:value-of select="BODY/P10"/></P> </font> </P> </font> </BLOCKQUOTE> <hr size="1" color="salmon"/> </BODY> </HTML> </xsl:for-each> </xsl:template> </xsl:stylesheet>
Take note of how I'm using the XSL statement <xsl:value-of/> to insert the data from the XML document, and how I create a hyperlink for the reporter's e-mail address using the <xsl:attribute/>, with this codeblock:
<a> <xsl:attribute name="href"> <xsl:value-of select="MAILTO"/> </xsl:attribute> <xsl:value-of select="REPORTER"/> </a>
And also how I insert an image in two different places in the story (I get asked how to do this one all the time), in this block:
<img> <xsl:attribute name="src"> <xsl:value-of select="REPORTERGRAPHIC"/> </xsl:attribute> </img>
NEWS-ARTICLE.XSL acts as a placeholder presenting the data with defined formatting in HTML when data from XML documents are loaded into it.
FORM.ASP
By all accounts, this is a normal Web form. The FormatDateTime function formats the date into the required format, and inserts it into the Date textbox on form.asp . This value is later inserted into the DATE node when the form is submitted:
<%=FormatDateTime(Date(),1)%>
Other than that, there's nothing really out of the ordinary going on here. Basic form fields are the order of the day, and the form uses the POST method to pass the data onto the CREATE-XML-DOC.ASP page for processing. The NAME attributes of each form field are used as the basis of our construction of child nodes in our XML document in the next step.
Here's the code for FORM.ASP:
<html> <head> <title> Publish a new story </title> </head> <body bgcolor="#c0c0c0"> <form action="create-xml-doc.asp" method="post"> <h3 align=center><FONT face=Tahoma><U><FONT size=5>Enter your story information</FONT></U> </FONT></h3><FONT face=Tahoma><FONT size=2><STRONG> Title: <input name="TITLE" width="65" style="WIDTH: 320px; HEIGHT: 22px"><br> Subhead: <input name="SUBHEAD" width="65" style="WIDTH: 320px; HEIGHT: 22px"><br> Reporter: <select size="1" name="REPORTER"> <option value="Sabrina Salas">Bri</option> <option value="Shawn Gumataotao">Shawn</option> <option value="Mindy Fothergill">Mindy</option> <option value="Yanna Person">Yanna</option> <option value="Jay Pascua">Jay</option> <option value="Rachel Taimanao">Rachel</option> <option value="Jason Salas">Jason</option> </select><br> E-mail address: <select size="1" name="MAILTO"> <option value="mailto:sabrina@kuam.com">sabrina@kuam.com</option> <option value="mailto:shawn@kuam.com">shawn@kuam.com</option> <option value="mailto:mindy@kuam.com">mindy@kuam.com</option> <option value="mailto:yanna@kuam.com">yanna@kuam.com</option> <option value="mailto:jay@kuam.com">jay@kuam.com</option> <option value="mailto:rachel@kuam.com">rachel@kuam.com</option> <option value="mailto:jason@kuam.com">jason@kuam.com</option> </select><br> Reporter Graphic: <select size="1" name="REPORTERGRAPHIC"> <option value="images/sabrina.jpg">Bri</option> <option value="images/shawn.jpg">Shawn</option> <option value="images/mindy.jpg">Mindy</option> <option value="images/yanna.jpg">Yanna</option> <option value="images/jay.jpg">Jay</option> <option value="images/rachel.jpg">Rachel</option> <option value="images/jason2.jpg">Jas</option> </select><br> Date: <input width="65" name="DATE" value="<%=FormatDateTime(Date(),1)%>"& - style="WIDTH: 215px; HEIGHT: 25px"><br> <hr width="85%" color="black"> <P><h3 align=center><u><FONT size=5>Enter your story's body</FONT> </u></h3> <P></P>Paragraph 1: <TEXTAREA style="WIDTH: 648px; HEIGHT: 38px" name=P1 cols=68></TEXTAREA><br> Paragraph 2: <TEXTAREA style="WIDTH: 648px; HEIGHT: 38px" name=P2 cols=48></TEXTAREA><br> Paragraph 3: <TEXTAREA style="WIDTH: 648px; HEIGHT: 38px" name=P3 cols=48></TEXTAREA><br> Paragraph 4: <TEXTAREA style="WIDTH: 648px; HEIGHT: 38px" name=P4 cols=48></TEXTAREA><br> Paragraph 5: <TEXTAREA style="WIDTH: 648px; HEIGHT: 38px" name=P5 cols=48></TEXTAREA><br> Paragraph 6: <TEXTAREA style="WIDTH: 648px; HEIGHT: 38px" name=P6 cols=48></TEXTAREA><br> Paragraph 7: <TEXTAREA style="WIDTH: 648px; HEIGHT: 38px" name=P7 cols=48></TEXTAREA><br> Paragraph 8: <TEXTAREA style="WIDTH: 648px; HEIGHT: 38px" name=P8 cols=48></TEXTAREA><br> Paragraph 9: <TEXTAREA style="WIDTH: 648px; HEIGHT: 38px" name=P9 cols=48></TEXTAREA><br> Paragraph 10: <TEXTAREA style="WIDTH: 648px; HEIGHT: 38px" name=P10 cols=48></TEXTAREA><br> <hr width="85%" color="black"> URL for story graphic: <input name="GRAPHIC" style="WIDTH: 434px; & - HEIGHT: 22px" size=19 value="http://www.kuam.com/images/news8_images/primetime.jpg"><br> Quote: <input name="QUOTE" style="WIDTH: 450px; HEIGHT: 22px"><br> Person being quoted: <input name="QUOTEDPERSON" style="WIDTH: 450px; HEIGHT: 22px"><br> Title of person being quoted: <input name="QUOTEDPERSONTITLE" style="WIDTH: 450px; HEIGHT: 22px"><br> </STRONG></FONT></FONT> <hr width="85%" color="black"> <input id="FILENAME" name="FILENAME"><BR><STRONG><FONT size=2>Filename for your XML file:<br> <input type="submit" id="btnSub" name="btnSub" value="Submit"></FONT></STRONG><br></FONT> </form> </body> </html>
CREATE-XML-DOC.ASP
This Active Server Page contains only script code that is used to build our XML documents, through the use of the Microsoft XML Document Object Model (MSXML DOM). It defines the structure of the XML document we planned out earlier. After declaring variables, it creates the root element of the XML document and named it STORIES by using the XML DOM createElement method. We then iterate through the document and create children of STORY , using the XML DOM appendChild method. Pay special attention to how the structure of the XML is defined by tacking specific child nodes onto their parents. The P1 through P10 nodes all are appended to the BODY node, as we defined above, with all other nodes falling under STORY .
In each node, we also call upon the .Text property of each node to populate it with data, which is retrieved from the Request.Form collection of FORM.ASP .
Now that the document has been created and filled with its data, we insert an XML processing instruction, which appears at the top of the document, to distinguish that this is in fact, an XML document. We then save the file to the Web server using the DOM's save content model, again using the value of the variable strFileName , which was retrieved from FORM.ASP .
' Create the XML processing instruction to tell the browser this is an XML document
Set objPI = objDom.createProcessingInstruction("xml", "version='1.0'")
objDom.insertBefore objPI, objDom.childNodes(0)
objDom.save "c:\inetpub\wwwroot\xmlnews\" & strFileName & ".xml"
Lastly, we call use the Response.Redirect method automatically advanced to QUERYSTRING.ASP and move to the next step in the process. We also insert a querystring value into the URL, the value of strFileName . This persists the value of the variable, as it will be extracted in the next step.
Response.Redirect ("querystring.asp?filename=" & strFileName)
At this point in the process, we've just created an XML document and populated it with data from the Web form. Next we'll create our ASP files dynamically. But first, here's the source code for CREATE-XML-DOC.ASP :>
<% @ Language = VBScript %> <% Dim objDom, objRoot, objChild1, objChild2, objChild3, objChild4, objPI Dim strFileName, objChild5, objChild6, objChild7, objChild8, objChild9 Dim objChild10, objChild11, objChild12, objChild13, objChild14 Dim objChildMailto, objChildSubHead, objChildStory, objChildQuote Dim objChildQuotedPerson, objChildQuotedPersonTitle, objChildGraphic Dim objChildReporterGraphic strFileName = Request.Form("FILENAME") ' CREATE AN XML DOCUMENT ' Create the root element Set objDom = Server.CreateObject("Microsoft.XMLDOM") Set objRoot = objDom.createElement("STORIES") objDom.appendChild objRoot ' Create a 1st-level child element Set objChildStory = objDom.createElement("STORY") objRoot.appendChild objChildStory ' Create 1st-level child elements under the STORY element Set objChild2 = objDom.createElement("DATE") objChildStory.appendChild objChild2 objChild2.Text = Request.Form("DATE") Set objChild1 = objDom.createElement("TITLE") objChildStory.appendChild objChild1 objChild1.Text = Request.Form("TITLE") Set objChildSubHead = objDom.createElement("SUBHEAD") objChildStory.appendChild objChildSubHead objChildSubHead.Text = Request.Form("SUBHEAD") Set objChild3 = objDom.createElement("REPORTER") objChildStory.appendChild objChild3 objChild3.Text = Request.Form("REPORTER") Set objChildReporterGraphic = objDom.createElement("REPORTERGRAPHIC") objChildStory.appendChild objChildReporterGraphic objChildReporterGraphic.Text = Request.Form("REPORTERGRAPHIC") Set objChildMailto = objDom.createElement("MAILTO") objChildStory.appendChild objChildMailto objChildMailto.Text = Request.Form("MAILTO") Set objChild4 = objDom.createElement("BODY") objChildStory.appendChild objChild4 objChild4.Text = Request.Form("BODY") Set objChildGraphic = objDom.createElement("GRAPHIC") objChildStory.appendChild objChildGraphic objChildGraphic.Text = Request.Form("GRAPHIC") Set objChildQuote = objDom.createElement("QUOTE") objChildStory.appendChild objChildQuote objChildQuote.Text = Request.Form("QUOTE") Set objChildQuotedPerson = objDom.createElement("QUOTEDPERSON") objChildStory.appendChild objChildQuotedPerson objChildQuotedPerson.Text = Request.Form("QUOTEDPERSON") Set objChildQuotedPersonTitle = objDom.createElement("QUOTEDPERSONTITLE") objChildStory.appendChild objChildQuotedPersonTitle objChildQuotedPersonTitle.Text = Request.Form("QUOTEDPERSONTITLE") ' The P1, P2, P3....PNth child elements fall under the ' STORY/BODY element to hold story paragraphs individually Set objChild5 = objDom.createElement("P1") objChild4.appendChild objChild5 objChild5.Text = Request.Form("P1") Set objChild6 = objDom.createElement("P2") objChild4.appendChild objChild6 objChild6.Text = Request.Form("P2") Set objChild7 = objDom.createElement("P3") objChild4.appendChild objChild7 objChild7.Text = Request.Form("P3") Set objChild8 = objDom.createElement("P4") objChild4.appendChild objChild8 objChild8.Text = Request.Form("P4") Set objChild9 = objDom.createElement("P5") objChild4.appendChild objChild9 objChild9.Text = Request.Form("P5") Set objChild10 = objDom.createElement("P6") objChild4.appendChild objChild10 objChild10.Text = Request.Form("P6") Set objChild11 = objDom.createElement("P7") objChild4.appendChild objChild11 objChild11.Text = Request.Form("P7") Set objChild12 = objDom.createElement("P8") objChild4.appendChild objChild12 objChild12.Text = Request.Form("P8") Set objChild13 = objDom.createElement("P9") objChild4.appendChild objChild13 objChild13.Text = Request.Form("P9") Set objChild14 = objDom.createElement("P10") objChild4.appendChild objChild14 objChild14.Text = Request.Form("P10") ' Create the XML processing instruction Set objPI = objDom.createProcessingInstruction("xml", "version='1.0'") objDom.insertBefore objPI, objDom.childNodes(0) objDom.save "c:\inetpub\wwwroot\xmlnews\" & strFileName & ".xml" ' Destroy all instantiated object referneces Set objDom = nothing Set objChild1 = nothing Set objChildStory = nothing Set objSubhead = nothing Set objChild2 = nothing Set objChild3 = nothing Set objChildReporterGraphic = nothing Set objChildMailto = nothing Set objChild4 = nothing Set objChildGraphic = nothing Set objChildQuote = nothing Set objChildQuotedPerson = nothing Set objChildQuotedPersonTitle = nothing Set objChild5 = nothing Set objChild6 = nothing Set objChild7 = nothing Set objChild8 = nothing Set objChild9 = nothing Set objChild10 = nothing Set objChild11 = nothing Set objChild12 = nothing Set objChild13 = nothing Set objChild14 = nothing Set objPI = nothing Response.Redirect ("querystring.asp?filename=" & strFileName) %>
QUERYSTRING.ASP
All this short script does is confirm to the user that the XML document has been created, and passes the user along to the page containing the script which will generate the ASP file, when the user clicks on the hyperlink.
We collect the variable strFileName with the Request.QueryString collection from the URL of CREATE-XML-DOC.ASP and regenerate this value by passing it along again in the URL, which we'll extract in the next page, NEW_STORY_TEMPLATE.ASP .
This is an ad hoc method of persisting variables, without the burden of cookies or complex session management.
<% @ Language = VBScript %> <% Dim strFileName strFileName = Request.QueryString("filename") Response.Write "<font face=tahoma size 2><b>Your story has been & - successfully created as an XML document.<br><br>&q Response.Write "<a href=new_story_template.asp?filename=" & strFileName & - ">Click here</a> to finish the process and create your story for our public Web site.</font>" %>
NEW_STORY_TEMPLATE.ASP
This is it - the last step towards automated bliss! What we're doing here is quite simple - we're writing out the ASP script we described earlier, and extracting the value of filename from the URL querystring. We do this in a subroutine so the code will not be executed immediately, until it is formally called at the bottom of the page. All this happens in a matter of milliseconds, but it's an example of good, disciplined code writing you should get in the habit of practicing. While the code may be lengthy, it's really very easy to follow.
<% @ Language = VBScript %> <% Sub CreateNewASP On Error Resume Next strFileName = Request.QueryString("filename") Set FSO = CreateObject("Scripting.FileSystemObject") Set newStory = FSO.CreateTextFile("c:\inetpub\wwwroot\xmlnews\" & strFileName & ".asp", False) newStory.Write("<!-- XML content starts here -->") newStory.Write(vbcrlf & "<%" & vbcrlf) newStory.Write("' Load the XML document") newStory.Write(vbcrlf & "Set source = Server.CreateObject(") newStory.Write(Chr(34) & "Microsoft.XMLDOM") newStory.Write(Chr(34) & ")") newStory.Write(vbcrlf & "source.async = false") newStory.Write(vbcrlf & "source.load(Server.MapPath(") newStory.Write(Chr(34) & strFileName) newStory.Write(".xml") newStory.Write(Chr(34) & ")") newStory.Write(")") newStory.Write(vbcrlf & vbcrlf) newStory.Write("' Load the XSL stylesheet") newStory.Write(vbcrlf & "Set style = Server.CreateObject(") newStory.Write(Chr(34) & "Microsoft.XMLDOM") newStory.Write(Chr(34) & ")") newStory.Write(vbcrlf & "style.async = false") newStory.Write(vbcrlf & "style.load(Server.MapPath(") newStory.Write(Chr(34) & "news-article.xsl") newStory.Write(Chr(34) & ")") newStory.Write(")") newStory.Write(vbcrlf & vbcrlf) newStory.Write("' Write out the page contents") newStory.Write(vbcrlf & "Response.Write(source.transformNode(style))") newStory.Write(vbcrlf & "%" & ">") newStory.Write(vbcrlf & "' Destroy all object references") newStory.Write(vbcrlf & "Set source = nothing") newStory.Write(vbcrlf & "Set style = nothing") newStory.Write(vbcrlf & "<!-- XML content ends here -->") newStory.Close If Err.Number > 0 Then Response.Write("<font face=tahoma size=3>Your story has <b>NOT</b> been & - created!<br>A file with the name <b>" & Chr(34) & strFileName & Chr(34) & - "</b> already exists.<br><br> <a href=javascript:history.go(-2)>Go & - back</a> and create it again!</font>") Err.Clear Else Response.Write("<font face=tahoma size=3><b>Your story was successfully published!</b></font>") End If ' Destroy the instantiated object's reference Set FSO = nothing End Sub %> <% Call CreateNewASP %>
By using VBScript's Write method on the FSO object we declared, we include all of the syntax for our script as a string. Note how we escape in and out of HTML by use of the VBScript concatenation operator ("&"), and use VBScript's special characters (i.e., Chr(34) for double-quotes) and liberal uses of Visual Basic's vbcrlf function to insert line breaks within the code so it all comes out nice in the finished product. Failing to include line breaks would produce the script all on a single line.
This script encapsulates your XML-generated content within HTML comment tags, which you can see are written to the page within the script. So when a user browses to your ASP file, all of the content entered through the Web form will be marked nicely with start and end points in the HTML source code:
<html><body>
... page information ... <!-- XML content starts here --> ... your content ... <!-- XML content ends here --> ... more page information ... </body></html>
To make life simpler, I decided to double-up on the amount of protection on filenames being created. If this was to be a truly distributed application with more than one user logging on and trying to create stories, at some point two or more people might attempt to write files with the same name at the same time. So, within the script block I include the " False " parameter on the CreateTextFile method to programmatically rule out files being overwritten should the data passed through the form with the same filename. This syntactically prevents the dangerous scenario of file being erased from ever occurring. Optionally, if you use this system for less frequent applications than daily news, you could change the parameter to " True ", or just leave it out altogether, and files with the same name swill just be overwritten without warning.
I couple this with the err or-trapping statement On Error Resume Next to create a customized error message to report to the user that an error has occurred, later down the page. Our End...If statement prints a conditional message to the browser, that lets the user know whether the ASP file was created...or not. This ensures that the error is stated while not crashing the entire program. It's an example of better management of your Web applications.
Lastly, we call our subroutine and execute our script:
<% Call CreateNewASP %>
What results is that a new text file gets written to the server in our application's directory ( C:\inetpub\wwwroot\xmlnews\ ), with the filename inserted automatically from the variable strFileName , which was the sole value extracted from the Request.Querystring collection and the file extension of ".ASP":
Set newStory = FSO.CreateTextFile("c:\inetpub\wwwroot\xmlnews\" & strFileName & ".asp", False)
We used the POST method to transmit the form data into the HTTP header information of NEW_STORY_TEMPLATE.ASP , and tweaked the additional parameter of hard-coding into the querystring the filename value from QUERYSTRING.ASP . Sneaky!
Because this is an internal app I personally am fanatical about seeing what's going on within the script, and what values and parameters are being passed from page-to-page. Alternatively, you could have accomplished the same thing (passing the value of strFileName ). This would prevent anyone from knowing the string which was entered by the user at the onset in FORM.ASP by using hidden values within the ASP pages and passing them on between pages in the app, extracting them as necessary. For example, the following will also work:
<input type="hidden" value="<%=Request("strFileName")%>">
The script also takes the value of strFileName and inserts it into the path to the XML document within the script, and then tacks on the file extension of " .XML ". This creates an association to the XML document that was created by CREATE-XML-DOC.ASP :
newStory.Write(vbcrlf & "source.load(Server.MapPath(") newStory.Write(Chr(34) & strFileName) newStory.Write(".xml") newStory.Write(Chr(34) & ")")
The output would then literally read:
source.load(Server.MapPath("strFileName.xml")
.and thus would create an Active Server Page, in which the content consists of the data contained in the XML document, rendered by the formatting instructions within the XSL stylesheet. You now have a one-to-one relationship for as many documents as you create, with one XML file corresponding to one ASP file.
Now that you have the back-end architecture for your system built, you should play with it by browsing to http://localhost/xmlnews and create a bunch of new files, viewing them in your browser. Mess around with the XSL stylesheet and develop a new presentation format
Congratulations! You've successfully built a functional document generation system that takes in data inputted into a Web form and spits out XML documents, which can be used for a number of applications. If you want to play around and expand on this concept, you can build a new XSL stylesheet and have a script bind to that one (for a mobile version of your site, for instance).
If I want to increase the number of ways people can access our information, I just create new XSL stylesheets. A good practical example is providing users with the popular "Print This Article" service that most news-oriented sites make available. I would just write a simple XSL stylesheet that displayed the same article content from the XML document without graphics, and a fancy layout, all tucked nicely within a table with a maximum width of 450 pixels, so it would print on most major printer models. I then create a new ASP file that binds to that XSL stylesheet, and I've got it!
Using XML in this fashion also helps for other developers, if they want to use our news headlines on their own homepages as syndicated they just simply build their own stylesheet(s) using XSL and import the data - the headlines only - with my site still getting the eventual page visit if a user clicks on the link. Thus, I extend the breadth of my market reach and still manage to maintain my traffic levels, retaining my advertising revenue.
The question I most often get asked when describing to Web developers the benefits of employing XML into their Web projects is "Couldn't I just have done this in HTML?" It's also the question I always wind up asking myself at the end of the day. Yes, you very well could have just created individual HTML files, but you can do so much more with much less work than if you had published individual static HTML files for each type of document you wanted. But it likely would not have been as easy. And for our second and third objectives of this lesson, Make Web publishing for multi-platform devices possible, and Make content syndication possible, this would be a more efficient way in the long run.
And that's what you should aim for: long-term success with your Web projects, whether it function as a marketing tool to entice users to buy a product off of your public Web site, or serve its purpose as an internal LAN or intranet application, creating documents for internal corporate use.
As in most things on the Web, there's no predefined template for building the perfect Web application.it's all up to the individual and what's best for his or her organization.
|
| |||||||
| |||||||||||||||
|
ASPToday is brought to you by
Wrox Press (http://www.wrox.com/). Please see our terms
and conditions and privacy
policy. ASPToday is optimised for Microsoft Internet Explorer 5 browsers. Please report any website problems to webmaster@asptoday.com. Copyright © 2001 Wrox Press. All Rights Reserved. |