Finding the value of the <title> in an HTML file using ASP - asp-classic

I am trying to create an automatically generate a table of contents page for a directory with a variable number of HTML files. I have created this:
<ul>
<%
dim fs,fo,x
set fs=Server.CreateObject("Scripting.FileSystemObject")
set fo=fs.GetFolder("c:\test\html\")
for each x in fo.files
newName=Split(x.Name, ".")
'Print the name of all files in the test folder
for each y in newName
Response.write("<li><a href='" & x.Name & "'>" & y & "</a></li>")
next
next
set fo=nothing
set fs=nothing
%>
</ul>
The problem here is that the links are generated using the file name, so I get things like "introduction" instead of "Introduction to This Topic." The html > head > title element in each HTML document is the link text I want to use. Is there a way I can extract it from each file?
(I am open to a solution that doesn't use ASP. I created this simply because it was what I had available to me. I'm not very familiar with ASP or its capabilities, so there might be a more efficient way to tackle this problem.)

There's no saying that all of the files in a folder are actually used and are part of a site, or how these files relate in a sitemap structure. It's better to approach this from a crawler on the outside than a file-system on the inside.
There are various sitemap generating services on the web that you can use. You can grab the results and edit them to suit your needs and post them as your own directory.

Related

Classic ASP render a template and send variables

I have a classic ASP page, and I need to create a loop for each row on a table and then create an html document and save it to the hard drive, but I want to create a template so I just send the two variables to the template so I don't have to write the HTML document each time on the loop.
This is what I have so far:
SQL = "select Title, Article from [ASPTest].[dbo].[articles]"
set rs = conn.execute(SQL)
arrRecs = rs.GetRows
For row = 0 To UBound(arrRecs, 2) 'Rows
For col = 0 To UBound(arrRecs, 1) 'Columns
Response.Write rs.Fields(col).Name & " = " & arrRecs(col, row) & " "
dim fs,f
set fs=Server.CreateObject("Scripting.FileSystemObject")
set f=fs.CreateTextFile("C:\Users\User\Documents\ASP Pages\"+arrRecs(col, row)+".html",true)
f.write("<html><body><div>It kinda works</div></body></html>")
f.close
set f=nothing
set fs=nothing
Next
Response.Write "<br />"
Next
Is there a way to use a template that has 2 variable holders and send the article name and title to the template and then save it to the disk?
Thank you.
I think you could probably achieve what you want using a template stored as a text file, and the Replace function.
Your template should be a fully-formed html page, but with placeholder values for the title and article. The placeholders need to be unique, so something like [[[~~~Title~~~]]] or a similar sequence that will not occur in your actual titles, articles, or the template itself.
<html>
<head><title>[[[~~~Title~~~]]]</title></head>
<body>
<h1>[[[~~~Title~~~]]]</h1>
<div id="article">[[[~~~Article~~~]]]</div>
</body>
</html>
In your code, read the template from the file and store it in a variable. (So technically, you could just write it to a variable in the first place, but VBScript is bad at string concatenation... anyway.) Get your array of titles & articles and loop through it (though only once: I'm not sure why you're looping through both rows and columns in your attempt). For each row, make a copy of the template, replace the title placeholder with the current row's title, replace the article placeholder with the current row's article, and write the result to a file.
Dim template, t
Dim fso, file
Dim rs, conn, SQL
Dim records, row
SQL = "SELECT ID, Title, Article FROM [ASPTest].[dbo].[articles]"
'[...database stuff...]
records = rs.GetRows
'[...close database...]
Set fso = Server.CreateObject("Scripting.FileSystemObject")
Set file = fso.OpenTextFile("path/to/template.txt",1) '- 1 = For reading
template = file.ReadAll
file.Close
Set file = Nothing
For row = 0 to UBound(records,2)
t = template
t = Replace(t,"[[[~~~Title~~~]]]",records(1,row))
t = Replace(t,"[[[~~~Article~~~]]]",records(2,row))
Set file = fso.CreateTextFile("path/to/html/" & records(0,row) & ".html")
file.Write(t)
file.Close
Set file = Nothing
Next
Set fso = Nothing
Back in the day I created the KudzuASP template engine to solve this rather complex deficiency in Classic ASP. In KudzuASP you can have ASP code pages that have absolutely NO HTML in them.
KudzuASP is as small include file roughly under 1000 lines of code that turns your hosting ASP page into an event driven object used by the template engine.
In short you create an instance of the template engine, set some variables, install custom code objects, and invoke it after which the template engine reads your template and make callbacks to your ASP page when and where appropriate. It has a library system so you can load libraries of custom tags handlers/components via code or by tags placed in your HTML template.
One of the best features is that for those still under the Classic ASP umbrella it makes 100% separation of application code and logic from presentation possible. Coding Classic ASP pages using KudzuASP is much easier than without and because of the way ASP compiles pages the callbacks are "native" and very fast.
You can find it here KudzuASP where the project is still maintained.

Write a file containing ASP delimiters

We have lots of files containing image / static file references to resources on our site. As we are moving these files to S3 hosting, I am writing a script that reads each of our ASP files, replaces each reference so that each one points at a globally defined variable, and rewrites those changes to the file, so that we don't have to update all these files manually!
This works alright with references inside actual code.
eg.
Response.Write "<img src=""http://www.site.com/images/image.gif"">"
becomes
Response.Write "<img src=""" & s3BucketName & "/images/image.gif"">"
But when it comes to replacing code like this :
<script src="/javascript/script.js">
It's more difficult - as we have to place the ASP delimiters <%= %>
around the global var around it.
eg.
<script src="<%=s3BucketName%>/javascript/script.js">
Because the script delimiters actually stop the page where they are, and generate an error, that's what I'm finding difficult. URLencoding the <%=s3BucketName%> string, and writing, just writes the encoded text (unusable by ASP), doesn't transform into what I want.
Any ideas gratefully received.
Thanks, Adam
Ok, I've come up with a solution, seems to work. If you find a better one, please comment.
textToReplace = "src="""& chr(60) & chr(37) & chr(61) & "s3BucketName" & chr(37) & chr(62) & "/javascript/script.js"
Basically each symbol of <%= and %> is converted into chr() values.
You could use the basetag in the head section of your pages then you can leave the relative urls like your script example alone, you can combine this technique with the one peedeeaay suggests.
<base href="http://www.s3bucketdomain.com/directory/" />

ASP.NET localized files

I've got a web page with a link, and the link is suppose to correspond to a PDF is the given user's language. I'm wondering where I should put these PDF files though. If I put them in App_LocalResources, I can't specify a link to /App_LocalResources/TOS_en-US.pdf can I?
The PDF should definitely not be in the App_LocalResources folder. That folder is only for RESX files.
The PDF files can go anywhere else in your app. For example, a great place to put them would be in a ~/PDF folder. Then your links will have to be dynamically generated (similar to what Greg has shown):
string cultureSpecificFileName = String.Format("TOS_{0}.pdf", CultureInfo.CurrentCulture.Name);
However, there are some other things to consider:
You need a way to ensure that you actually have a PDF for the given language. If someone shows up at your site and has their culture specified as Klingon, it's unlikely that you have such a PDF.
You need to decide exactly what the file format will be. In the example given, the file would have to be named TOS_en-US.pdf. It you want to use the 2-letter ISO culture names, use CurrentCulture.TwoLetterISOLanguageName and then the file name would be TOS_en.pdf.
I would store the filename somewhere with an argument in it (i.e. "TOS_{0}.pdf" ) and then just add the appropriate suffix in code:
string cultureSpecificFileName = string.Format("TOS_{0}.pdf", CultureInfo.CurrentCulture);
Does the PDF have to have the same file name for each of the different languages? If not, put them all into a directory and just store the path in your resources file.

How to select between include files

I am working on adding a mulit-language feature to an asp classic site. I was trying to do this by using if else statements to select the include I want to load. After a bit of research I found out that includes files are loaded up before any code is handled.
How can I get around this issue and load up the proper include files? Is there a better way of doing this?
Thanks!
You can't, as you've discovered, dynamically choose includes. Includes are handled statically before any script is executed.
The next best thing is Server.Execute. You can use logic to choose what additional files to execute, however whether this fits with your solution is another matter. What do your includes currently contain?
Another approach would be place your "multi-language" choices in some data format such a set of CSV files or XML files. Your code would then load the appropriate "language file".
After countless hours I think I finally came up with a solution. I create xml files for each language (en.xml, fr.xml) with a super simple structure (just a label element with an id and value).
By using an attribute that has a similar name to the label I want to replace I can figure out where everything needs to go, and just pull the value.
I'm not sure if this idea helps, but you could dim the language string variables in one ASP file and then set the variables in separate ASP functions. Then your if statements can call the proper function to set the ASP language string variables. You would not be breaking out the language string into separate files, but it might accomplish what you are trying to achieve.
For example:
dim str1, str2
sub SetLangX
str1 = "String val 1 for lang X"
str2 = "String val 2 for lang X"
end sub
sub SetLangY
str1 = "String val 1 for lang Y"
str2 = "String val 2 for lang Y"
end sub
It can be done - just use include virtual instead of file
edit
I stand corrected - obviously i tried too hard to forget those dark ages.
Years ago i worked on a project where we would create a "container page" for every language version an then include the respective portion of constants.
A working spinoff is still running and if you check the page source of this site you can get an idea how we plugged the pages together.
Some of the included scripts identified by their SVN id tags even included more scripts and maintaining this slowly turned into a nightmare.
I'm sorry i was wrong about the conditional include and there should be a better solution than the one mentioned above.

is it possible to issue dynamic include in asp-classic?

I mean, like php'h include...
something like
my_file_to_be_included = "include_me.asp"
-- >
for what I've seen so far, there are a couple of alternatives, but every one of them has some sort of shortcoming...
what I'm trying to figure out is how to make a flexible template system... without having to statically include the whole thing in a single file with a loooooong case statement...
here there are a couple of links
a solution using FileSysmemObject, just lets you include static pages
idem
yet another one
same thing from adobe
this approach uses Server.Execute
but it has some shortcomings I'd like to avoid... seems like (haven't tried yet) Server.Execute code runs in another context, so you can't use it to load a functions your are planning to use in the caller code... nasty...
same thing
I think this one is the same
this looks promising!!!
I'm not sure about it (couldn't test it yet) but it seems like this one dinamycally handles the page to a SSDI component...
any idea???
No you can't do a dyanmic include, period.
Your best shot at this is a server.execute and passing whatever state it needs via a Session variable:-
Session("callParams") = BuildMyParams() 'Creates some sort of string
Server.Execute(my_file_to_be_included)
Session.Contents.Remove("callParams")
Improved version (v2.0):
<%
' **** Dynamic ASP include v.2.0
function fixInclude(content)
out=""
if instr(content,"#include ")>0 then
response.write "Error: include directive not permitted!"
response.end
end if
content=replace(content,"<"&"%=","<"&"%response.write ")
pos1=instr(content,"<%")
pos2=instr(content,"%"& ">")
if pos1>0 then
before= mid(content,1,pos1-1)
before=replace(before,"""","""""")
before=replace(before,vbcrlf,""""&vbcrlf&"response.write vbcrlf&""")
before=vbcrlf & "response.write """ & before & """" &vbcrlf
middle= mid(content,pos1+2,(pos2-pos1-2))
after=mid(content,pos2+2,len(content))
out=before & middle & fixInclude(after)
else
content=replace(content,"""","""""")
content=replace(content,vbcrlf,""""&vbcrlf&"response.write vbcrlf&""")
out=vbcrlf & "response.write """ & content &""""
end if
fixInclude=out
end function
Function getMappedFileAsString(byVal strFilename)
Dim fso,td
Set fso = Server.CreateObject("Scripting.FilesystemObject")
Set ts = fso.OpenTextFile(Server.MapPath(strFilename), 1)
getMappedFileAsString = ts.ReadAll
ts.close
Set ts = nothing
Set fso = Nothing
End Function
execute (fixInclude(getMappedFileAsString("included.asp")))
%>
Sure you can do REAL classic asp dynamic includes. I wrote this a while back and it has opened up Classic ASP for me in a whole new way. It will do exactly what you are after, even though people seem to think it isn't possible!
Any problems just let me know.
I'm a bit rusty on classic ASP, but I'm pretty sure you can use the Server.Execute method to read in another asp page, and then carry on executing the calling page. 15Seconds had some basic stuff about it - it takes me back ...
I am building a web site where it would have been convenient to be able to use dynamic includes. The site is all ajax (no page reloads at all) and while the pure-data JSON-returning calls didn't need it, all the different html content for each different application sub-part (window/pane/area/form etc) seems best to me to be in different files.
My initial idea was to have the ajax call be back to the "central hub" main file (that kicks the application off in the first place), which would then know which sub-file to include. Simply including all the files was not workable after I realized that each call for some possibly tiny piece would have to parse all the ASP code for the entire site! And using the Execute method was not good, both in terms of speed and maintenance.
I solved the problem by making the supposed "child" pages the main pages, and including the "central hub" file in each one. Basically, it's a javascript round-trip include.
This is less costly than it seems since the whole idea of a web page is that the server responds to client requests for "the next page" all the time. The content that is being requested is defined in scope by the page being called.
The only drawback to this is that the "web pieces" of the application have to live partly split apart: most of their content in a real named .asp file, but enough of their structure and relationship defined in the main .asp file (so that, for example, a menu item in one web piece knows the name to use to call or load another web piece and how that loading should be done). In a way, though, this is still an advantage over a traditional site where each page has to know how to load every other page. Now, I can do stuff like "load this part (whether it's a whole page or otherwise) the way it wants to be loaded".
I also set it up so each part can have its own javascript and css (if only that part needs those things). Then, those files are included dynamically through javascript only the first time that part is loaded. Then if the part is loaded repeatedly it won't incur an extra overhead.
Just as an additional note. I was getting weird ASCII characters at the top of the pages that were using dynamic includes so I found that using an ADODB.Stream object to read the include file eliminated this issue.
So my updated code for the getMappedFileAsString function is as follows
Function getMappedFileAsString(byVal strFilename)
Dim fso
Set fso = CreateObject("ADODB.Stream")
fso.CharSet = "utf-8"
fso.Open
fso.LoadFromFile(Server.MapPath(strFilename))
getMappedFileAsString = fso.ReadText()
'Response.write(getMappedFileAsString)
'Response.End
Set fso = Nothing
End Function

Resources