利用JavaDoc制作windows的CHM文档

束俊英
2023-12-01
使用了开源的一个ruby脚本来利用JavaDoc制作windows的CHM文档。

输出文件编码的时候一定记得选择中文,例如file.puts "Language=0x804 Chinese"。
def createProjectFile(prjname, basedir)

packages = scanPackageTree(basedir)

createContentsFile(prjname+'.hhc', basedir, packages)
createIndexFile(prjname+'.hhk', basedir, packages)

assetsexplise = /^$/
title = getIndexTitle(basedir)

file = open(prjname+'.hhp', 'w')
file.puts "[OPTIONS]"
file.puts "Compatibility=1.1 or later"
file.puts "Compiled file=#{prjname}.chm"
file.puts "Contents file=#{prjname}.hhc"
file.puts "Default Window=default"
file.puts "Display compile progress=Yes"
file.puts "Default topic=#{basedir}/overview-summary.html"
file.puts "Full-text search=Yes"
file.puts "Index file=#{prjname}.hhk"
# file.puts "Language=0x411 Japanese"
file.puts "Language=0x409 English (U.S.)"
# file.puts "Language=0x804 Chinese"
file.puts "Title=#{title}"
file.puts ""
file.puts "[WINDOWS]"
file.puts "default=\"#{title}\",\"#{prjname}.hhc\",\"#{prjname}.hhk\",\"#{basedir}/overview-summary.html\",\"#{basedir}/overview-summary.html\",,,,,0x2520,,0x384e,,,,,,,,0"
file.puts ""
file.puts ""
file.puts "[FILES]"
collectAssets(basedir, assetsexplise).each() do |path|
file.puts(path)
end
file.puts ""
file.close()
end

def getIndexTitle(basedir)
title = ""
open(basedir + '/index.html', 'r') do |fh|
fh.read() =~ /\<title\>\n*(.+?)\n*\<\/title\>/i
title = $1
end
return title
end

def collectAssets(assetsdir, assetsexplise)
assets = []
Dir.foreach(assetsdir) do |asset|
assetpath = assetsdir + '/' + asset
if File.stat(assetpath).ftype == 'file' then
assets.push(assetpath) unless assetsexplise =~ assetpath
elsif File.stat(assetpath).ftype == 'directory' and asset[0,1] != '.' then
assets.concat(collectAssets(assetpath, assetsexplise))
end
end
return assets
end

HEADER = '<HTML><HEAD><meta name="GENERATOR" content="Microsoft® HTML Help Workshop 4.1"><!-- Sitemap 1.0 --></HEAD><BODY><OBJECT type="text/site properties"></OBJECT>'
FOOTER = '</BODY></HTML>'

def createContentsFile(filename, basedir, packages)

file = open(filename, 'w')
file.puts HEADER

file.puts "[list]"
file.puts "\t" + '<LI> <OBJECT type="text/sitemap">'
file.puts "\t" * 2 + '<param name="Name" value="Overview">'
file.puts "\t" * 2 + '<param name="Local" value="' + basedir + '/overview-summary.html">'
file.puts "\t" * 2 + '<param name="ImageNumber" value="21">'
file.puts "\t" * 2 + '</OBJECT>'

packages.each() do |pkg|
file.puts "\t" + formatTopicItem(pkg['name'], basedir+'/'+pkg['file'])
file.puts "\t" * 1 + "[list]"
pkg['classes'].each() do |cls|
file.puts "\t" * 2 + formatTopicItem(cls['name'], basedir+'/'+cls['file'])
file.puts "\t" * 2 + "[list]"
cls['details'].each() do |det|
file.puts "\t" * 3 + formatTopicItem(det, basedir+'/'+cls['file']+'#'+det)
end
file.puts "\t" * 2 + "[/list]"
end
file.puts "\t" * 1 + "[/list]"
end
file.puts "[/list]"

file.puts FOOTER
file.close()
end

def createIndexFile(filename, basedir, packages)

file = open(filename, 'w')
file.puts HEADER

indexes = {}
packages.each() do |pkg|
addKeywordToIndex(indexes, pkg['name'], pkg['name'], basedir+'/'+pkg['file'])
pkg['classes'].each() do |cls|
addKeywordToIndex(indexes, cls['name'], pkg['name']+'.'+cls['name'], basedir+'/'+cls['file'])
cls['details'].each() do |det|
addKeywordToIndex(indexes, det, pkg['name']+'.'+cls['name']+'.'+det, basedir+'/'+cls['file']+'#'+det)
end
end
end

file.puts "[list]"
indexes.keys.sort.each() do |keyword|
file.puts "\t" + formatIndexItem(keyword, indexes[keyword])
end
file.puts "[/list]"

file.puts FOOTER
file.close()
end

def addKeywordToIndex(indexes, keyword, detail, file)
if indexes[keyword] == nil then indexes[keyword] = {} end
indexes[keyword][detail] = file
end


def scanPackageTree(basedir)
packagelist = []
rxpkg = /\<A\s+HREF\=\"([\w\d\-\/]+?)\/package\-frame\.html\"\s+target\=\"packageFrame\"\>([\w\d\.]+)\<\/A\>/i
rxcls = /\<A\s+HREF\=\"([^\.][\w\d\-\.]+?)\"(\s+title\=\".+\")?\s+target\=\"classFrame\"\>(\<I\>)?([\w\d\.]+)(\<\/I\>)?\<\/A\>/i

IO.foreach(basedir + "/overview-frame.html") do | line |
if (line =~ rxpkg) != nil then
pkgdir = $1
pkgname = $2
print "#{pkgname}\n"
classes = []
IO.foreach(basedir + '/' + pkgdir + '/package-frame.html') do | line |
if (line =~ rxcls) != nil then
classfile = $1
classname = $4
print "#{pkgname}.#{classname}\n"
details = scanClassDocument(basedir+'/'+pkgdir+'/'+classfile)
classes.push({'name'=>classname, 'file'=>pkgdir+'/'+classfile, 'details'=>details})
end
end
pkgfile = pkgdir + '/package-summary.html'
packagelist.push({'name'=>pkgname, 'file'=>pkgfile, 'classes'=>classes})
end
end
return packagelist
end

def scanClassDocument(file)
scanstarts = false
anchors = []
IO.foreach(file) do |line|
if (line =~ /\<A\s+NAME\=\"([^\"]+)\"\>/i) != nil then
aname = $1
if (aname =~ /\w+_detail$/i) != nil then
scanstarts = true
elsif (aname =~ /^navbar_\w+/i) != nil then
scanstarts = false
else
if scanstarts then
anchors.push(aname)
end
end
end
end
return anchors
end

def formatTopicItem(name, href)
out = '<LI><OBJECT type="text/sitemap">'
out += sprintf('<param name="Name" value="%s">', name)
if href != nil then
out += sprintf('<param name="Local" value="%s">', href)
end
out += "</OBJECT>"
return out
end

def formatIndexItem(name, details)
out = '<LI><OBJECT type="text/sitemap">'
out += sprintf('<param name="Name" value="%s">', name)
details.keys.each() do |det|
out += sprintf('<param name="Name" value="%s">', det)
out += sprintf('<param name="Local" value="%s">', details[det])
end
out += "</OBJECT>"
return out
end

createProjectFile(ARGV[0], ARGV[1])


将JavaDoc的根目录拷贝到ruby脚本所在的目录下,这样会避免相对路径的问题,脚本里面处理得不好。安装好ruby环境([color=red]因为兼容性的问题,推荐使用ruby1.8[/color])之后,执行命令ruby createhhp.rb <help-file-basename> <javadoc-dir>,会在当前目录下生产hhc(目录)、hhk(索引)、hhp(项目)这三个文件。

记得去微软的官方站下载HTML Help Workshop。用HTML Help Workshop打开hhp文件就可以编译出正确的CHM文档。
 类似资料: