 Inside Technique : Building a Content Server with XML and ASP : Saving Files
Saving an article takes a few steps. The first step is to verify that the article is valid XML.
After validating the article, depending on if the user creates a new article or updated an existing one,
slightly different actions occur. For new articles we:
- get the next available article ID,
- insert the new article into the index,
- write the new index to disk,
- write the article to disk,
- and finally clear the index from the disk cache.
For existing articles, we
- find the existing article in the index,
- update the title and author,
- write the index to disk,
- overwrite the existing article on disk,
- and finally clear the index and article from the disk cache
The first step is to validate the XML. The script that validates the XML merely
ensures the XML is valid. In a production environment, you are also going to want
to validate the articles against a DTD to ensure that they are really articles.
This should be done so you can ensure reasonable results when the article is applied
to the XSL sheet. We test the article by simply trying to parse it with the XML parser:
' Get the submitted story
sStory = request.form("story")
' Instantiate the parser
set sourceFile = Server.CreateObject("Microsoft.XMLDOM")
sourceFile.async = false
' Try loading the story
if not sourceFile.loadXML(sStory) then
' Returns false if fails
response.write(reportParseError(sourceFile.parseError))
else
' parsed successfully
' do save here...
end if
Once successfully parsed, we need to save the document.
Depending on if the edited article is new or an existing one we have slightly different processing.
For existing articles, we locate the article node in the index, update as appropriate, and then save
the new article to disk. The process for updating the article is the reverse of how we retrieved existing articles.
' parsed successfully
if (storyid<>"") then
set nodeStory = getNode(indexFile,storyID)
if not nodeStory is nothing then
' Story found
' Update title and author by finding
' title and author text nodes
nodeStory.selectsinglenode("title[.]").text=sTitle
nodeStory.selectsinglenode("author[.]").text = sAuthor
' Write the existing story to disk
sourceFile.save(server.mappath("src/" & (storyid) & ".xml"))
end if
else
' New Article
end if
Adding articles is a bit more involved. We chose to manually construct the
sub-tree representing the article. This involves creating the individual article,
id, title, and author nodes and then inserting them into the appropriate part of
the document.
' Get the next article id
Set nodeStory = indexFile.selectSingleNode("storyindex")
if nodeStory.hasChildNodes then
Set nodeArticle = nodeStory.lastChild
idArticle = nodeArticle.selectSingleNode("id").text
else
idArticle = 0
end if
Set nodeNew = indexFile.createNode(1,"article","")
Set nodeID = indexFile.createNode(1,"id","")
Set nodeText = indexFile.createTextNode(idArticle+1)
nodeID.appendChild(nodeText)
Set nodeTitle = indexFile.createNode(1,"title","")
Set nodeTitleText = indexFile.createTextNode(sTitle)
nodeTitle.appendChild(nodeTitleText)
Set nodeAuthor = indexFile.createNode(1,"author","")
Set nodeAuthorText = indexFile.createTextNode(sAuthor)
nodeAuthor.appendChild(nodeAuthorText)
nodeNew.appendChild(nodeID)
nodeNew.appendChild(nodeTitle)
nodeNew.appendChild(nodeAuthor)
nodeStory.appendChild(nodeNew)
storyID = idArticle + 1
sourceFile.save(server.mappath("src/" & storyID & ".xml"))
We create nodes using the createNode method. Text is inserted
into the node using the createTextNode method. Finally, the nodes
can be combined using the appendChild method. Walking through the
above script step-by-step to add an article, we build up the following
tree (for a new article with the ID of 3):
Step 1
Set nodeNew = indexFile.createNode(1,"article","")
Set nodeID = indexFile.createNode(1,"id","")
Set nodeText = indexFile.createTextNode(idArticle+1)
nodeID.appendChild(nodeText)
Generates...
article id
|
"3"
Step 2
Set nodeTitle = indexFile.createNode(1,"title","")
Set nodeTitleText = indexFile.createTextNode(sTitle)
nodeTitle.appendChild(nodeTitleText)
Generates...
article id title
| |
"3" "Cool New Article"
Step 3
Set nodeAuthor = indexFile.createNode(1,"author","")
Set nodeAuthorText = indexFile.createTextNode(sAuthor)
nodeAuthor.appendChild(nodeAuthorText)
Generates...
article id title author
| | |
"3" "Cool New Article" "Scott"
Step 4
nodeNew.appendChild(nodeID)
Generates...
article title author
| | |
id "Cool New Article" "Scott"
|
"3"
Step 5
nodeNew.appendChild(nodeTitle)
Generates...
article author
| |
+-----+-----+ |
id title "Scott"
| |
"3" "Cool New Article"
Step 6
nodeNew.appendChild(nodeAuthor)
Generates...
article
|
+------------+------------+
id title Author
| | |
"3" "Cool New Article" "Scott"
This entire sub-tree is then inserted back into the index.xml file.
If you are familiar to innerHTML and outerHTML methods in DHTML, this approach
may appear more tedious. However, this approach provides greater control (especially
when editing existing elements) and is much less error-prone as you are not manipulating
a string representation of the elements.
The last remaining action in the editor is to delete an article.
Deleting the article is extremely simple. We just need to remove the
article node from the index:
if request.form("Delete")<>"" and storyid<>"" then
' Delete the Story
Set indexFile = Server.CreateObject("Microsoft.XMLDOM")
indexFile.async = false
indexFile.load server.mappath("src/index.xml")
if (indexFile.parseError.errorCode <> 0) then
response.write(reportParseError(indexFile.parseError))
else
' Find story
set nodeStory = indexFile.selectSingleNode("storyindex/article[id[.=" _
& chr(34) & storyid & chr(34) & "]]")
if not nodeStory is nothing then
' Remove node
nodeStory.parentNode.removeChild(nodeStory)
' Save new index
indexFile.save(server.mapPath("src/index.xml"))
response.write("<B>Deleted</B><P>")
' Remove cached files
delFile(server.mappath("cache/index.inc"))
delFile(server.mappath("cache/" & storyID & ".inc"))
' We purposely leave the raw XML file on disk
' to enable last resort recovery
storyID=""
end if
end if
end if
When reviewing our implementation, you should understand a
design decision that simplifies how our content server updates the index file.
Our system has no intelligent locking mechanism or transaction processing. To an
end-user this means our system should not be used in a high-volume collaborative environment.
If two users were to save an article at the same time, there is the risk one of the
articles will overwrite the other since we do not ensure that the next index is valid.
The same holds true if an existing article is saved at the same time a new article is added.
One of the operations may not be properly saved. In an environment with few or very
infrequent edits, our decision may never expose any problems. In either case, you need
to be aware of this.
This concludes the discussion of the Content Server implementation. Next we explain
how to download and install the sample files. Since
we presented the ASP scrpts in fragments, we recommend you download the sample files
to see the script in its entirety.
© 1997-2000 InsideDHTML.com, LLC. All rights reserved.
|