实现 Access 2007“HTML 报告”的更好方法
Posted
技术标签:
【中文标题】实现 Access 2007“HTML 报告”的更好方法【英文标题】:Better way to implement an Access 2007 "HTML Report" 【发布时间】:2011-01-24 20:04:56 【问题描述】:我需要制作一个类似“静态 html”的常见问题解答文档,供项目内部使用。
我将所有项目作为记录(问题、答案、类别)放入 Access 2007 数据库中,然后构建了一个报告,该报告使用子报告创建目录作为内部链接,然后列出所有问题和答案。该报告是一堆带有动态生成的 html 代码的文本区域(显然我还没有足够的信誉来发布图像,所以 http://i115.photobucket.com/albums/n299/SinbadEV/ReportCapture.png)...我只是将报告导出到一个文本文件,然后将其重命名为 . html 并在浏览器中打开。
我认为必须有一种不那么邪恶的方法来做到这一点。
【问题讨论】:
好主意,因为你会遇到这种方法的问题。这个方法很聪明,我用它来生成复杂的 XML 文件,但是 Access 有一个错误:当您将报告导出为文本时,有时会交换行!它们在预览中看起来不错,但在最终的文本文件中,页面的最后一行“上升”了 2 或 4 行。并且您的 xml(在您的情况下为 html)不再有效。我最终用 VBA 重写了所有内容,回到了循环和中断的美好时光。 我经常使用 HTML 使用一点 VBA 创建报告。我发现我可以在备忘录字段中将大量标准内容保存为模板,然后只需交换可变数据即可。 【参考方案1】:我现在使用来自 SinbadEV 和 awrigley 的想法在 MS Access 2007 中创建具有专业外观的 HTML 报告。就我而言,我不得不使用另一个技巧:
我发现,由于 MS Access 中的一些错误,它没有正确地将报告保存为 txt 格式。有时它会丢失很多信息,即使它显示在屏幕上。我也看到了问题,这里提到有时会访问混合线。它似乎取决于几个因素,例如报告和数据是否跨越 MS Acess 报告中的页面。
但是我发现,导出到 *.rtf 确实可以正常工作。因此,方法是制作 MS Acess 报告,将其保存到文本文件中时会创建一个 HTML 代码(就像 SinbadEV 所描述的那样),但是您首先需要将其保存到 *rtf。之后,您需要使用 MS Word 自动化将 *.rtf 转换为 txt 文件,并为其赋予 .html 扩展名(实际上并不需要太多努力)。
除了 MS Word 自动化之外,您还可以使用 Doxillion Document Converter 之类的工具从命令行将 rtf 转换为文本格式。
您可以在会议记录、问题、风险、协议、行动、项目跟踪工具 (http://sourceforge.net/projects/miraapt/) 中查看具有此功能的数据库。
【讨论】:
【参考方案2】:Application对象中有一个ExportXML方法,可以用XML导出数据库对象(表格、报告等)。如果要为浏览器格式化,则需要 XSL 样式表或 XSTL 文档:
http://msdn.microsoft.com/en-us/library/bb258194(v=office.12).aspx
我会说这是“规范”的做法。 OTOH 编写 XSL 和 XSTL 并不是一件有趣的事情,如果您的 HTML 生成器工作正常,那么您应该保持原样。 (实际上,恕我直言,这是一个不错的技巧)。
【讨论】:
虽然我可能最终决定使用我当前的方法或 VBA 代码,但这似乎是我问题的“正确”答案。该项目的优先级较低,因此我还没有开始实施任何提出的想法,但我发现一个页面专门解释了如何创建和 XSLT 为类似数据提供目录,我认为我可以对其进行改造以满足我的需求目标:dpawson.co.uk/xsl/sect2/N7402.html 我目前卡在这个,示例代码不起作用,只是手动选择导出报告或查询结果会生成一个带有 dataroot 节点但不包含数据的 XML 文件。跨度> 【参考方案3】:我看不出你所做的任何事情本质上是“邪恶的”。我为(现已停刊的杂志)Smart Access 写了一篇文章,出于不同的原因使用了类似的技术。 HTML 报告是副产品。从本质上讲,我的技术允许使用 Access 创建非常广泛的 word 文档,这些文档像键入的文本一样流动,而不是看起来像使用框创建的报告。
您仍然可以阅读 MSDN 上的文章: Extending Access Reports With Word and HTML
诀窍是使用您正在做的报告生成 HTML,然后使用自动化,在 Word 中打开 .html 文件并将其另存为 RTF。
我们使用该技术为约克教区创建了一个 300 页的目录。它完美无缺。
【讨论】:
【参考方案4】:以防万一您想采用 VBA 方式:我编写了一些可以使其变得非常简单的函数:
创建包含您要输出的数据的查询,然后打开查询并循环遍历所有记录,使用下面的函数 rRsToXml 将数据输出到文本文件。
Option Compare Database
Option Explicit
Function fRsToXml(rs As Recordset, Optional ignorePrefix As String = "zz", _
Optional ignoreNulls As Boolean = False) As String
'<description> Returns an XML string with all fields of the current record,
' using field names as tags.
' Field names starting with "zz" (or other special prefix) are ignored</description>
'<parameters> rs: recordset (byRef, of course)</parameters>
'<author> Patrick Honorez - www.idevlop.com </author>
Dim f As Field, bPrefLen As Byte
Dim strResult As String
bPrefLen = Len(ignorePrefix)
For Each f In rs.Fields
If Left(f.Name, bPrefLen) <> ignorePrefix Then 'zz fields are ignored !
If (Not ignoreNulls) Or (ignoreNulls And Not IsNull(f.Value)) Then
strResult = strResult & xTag(f.Name, f.Value) & vbCrLf
End If
End If
Next f
fRsToXml = strResult
End Function
Function xTag(ByVal sTagName As String, ByVal sValue, Optional SplitLines As Boolean = False) As String
'<description> Create an xml node and returns it as a string </description>
'<parameters> <sTagName> name of the tag </sTagName>
' <sValue> string to embed </sValue>
' <SplitLine> True to include CrLf at the end of each line
' (optional - default = False) </SplitLine></parameters>
'<author> Patrick Honorez - www.idevlop.com </author>
'<note> Make sure sValue does not contains XML forbidden characters ! </note>
'<changelog>
'</changelog>
Dim strNl As String, intAmp
If SplitLines Then
strNl = vbCrLf
Else
strNl = vbNullString
End If
xTag = "<" & sTagName & ">" & strNl & _
Nz(sValue, "") & strNl & _
"</" & sTagName & ">" '& strNl
End Function
Function CleanupStr(strXmlValue) As String
'<description> Replace forbidden char. &'"<> by their Predefined General Entities </description>
'<author> Patrick Honorez - www.idevlop.com </author>
Dim sValue As String
If IsNull(strXmlValue) Then
CleanupStr = ""
Else
sValue = CStr(strXmlValue)
sValue = Replace(sValue, "&", "&") 'do ampersand first !
sValue = Replace(sValue, "'", "'")
sValue = Replace(sValue, """", """)
sValue = Replace(sValue, "<", "<")
sValue = Replace(sValue, ">", ">")
CleanupStr = sValue
End If
End Function
【讨论】:
【参考方案5】:我曾经欺骗报告生成器为我制作 html 文档,但这种方法有局限性。首先,当您运行报告时,它会生成相当难看的 html,而不是可打印的报告。运行报表后还有更多工作可以将报表转换为漂亮的 html 文档,该文档可以在文字处理器中打开,然后保存为常规文档。 LibreOffice 通常比 ms-word 更适合接收生成的 html 文档,但偶尔 LibreOffice 无法完成这项工作(有一段时间它在链接图像方面存在问题)。文字处理器会忽略 css 样式,所以不要打扰样式,直接格式化仍然可以很好地工作,特别是对于文本是表格。如果所有导出的数据都在 html 表格中,那么使用 LibreOffice,因为 LibreOffice 可以根据 h1、h2、h3 标题生成目录,而 ms-word 不能。
这些天来,我只是将整个报告编写为 VBA 标准模块中的一个过程。我仍然不使用面向对象的代码,也没有理由在这里。完全用 VBA 编写的报告可以比标准 ms-Access 报告设计器生成的复杂得多。报告设计器报告需要大量修改才能使格式正确,这会耗费时间。对于复杂的报表,VBA 方法实际上更快。用 VBA 编写的报告可以每隔一秒运行一次,因此很容易调整表格的列宽等内容,并重新运行报告以检查输出。使用 VBA 创建的 html 报告被写为 html 文件,ms-access 可以发出 shell 命令以在 Web 浏览器中打开报告。如果浏览器已打开,则新报告会在新选项卡中打开,因此您可以看到以前版本的外观,因为此版本仍将在另一个选项卡中打开。
在标准模块(而不是表单模块)中编写报告,并从表单上的某些按钮单击事件中调用它。报告只需要被告知标题是什么,输出文件名和位置是什么以及报告应该输出的数据范围。报告过程包含创建报告所需的所有其他逻辑。以下是在我的一个应用程序中触发报告的调用过程。调用代码的目的是在分隔的文本文件中导出带有地理标记的照片列表,以便我可以在地图上绘制照片位置。导出 html 文件的过程非常相似。一些自定义函数在下面的代码中,但结构应该是可识别的。
Private Sub cmdCSV_File_Click()
Dim FolderName As String
Dim FileName As String
Dim ReportTitle As String
Dim SQL As String
Dim FixedFields As String
Dim WhereClause As String
Dim SortOrder As String
'Set destination of exported data
FolderName = InputBox("Please enter name of folder to export to", AppName, mDefaultFolder)
If mPaths.FolderExists(FolderName).Success Then
mDefaultFolder = FolderName 'holds default folder name in case it is needed again
Else
MsgBox "Can't find this folder", vbCritical, AppName
Exit Sub
End If
FileName = CheckTrailingSlash(FolderName) & "PhotoPoints.txt"
'Set Report Title
If Nz(Me.chkAllProjects, 0) Then
ReportTitle = "Photos from all Projects"
ElseIf Nz(Me.SampleID, 0) Then
ReportTitle = "Photos from Sample " & Me.SampleID
ElseIf Nz(Me.SurveyID, 0) Then
ReportTitle = "Photos from Survey " & Me.SurveyID
ElseIf Nz(Me.ProjectID, 0) Then
ReportTitle = "Photos from Project " & Me.ProjectID
Else
MsgBox "Please select a scope before pressing this button", vbExclamation, AppName
Exit Sub
End If
'Update paths to photos
If Have(Me.ProjectID) Then
WhereClause = " (PhotoPath_ProjectID = " & Me.ProjectID & ")" 'also covers sample and survey level selections
Else
WhereClause = " True" 'when all records is selected
End If
Call mPhotos.UpdatePhotoPaths(WhereClause) 'refreshes current paths
'Set fixed parts of SQL statement
FixedFields = "SELECT Photos.*, PhotoPaths.PhotoPath_Alias, PhotoPaths.CurrentPath & Photos.PhotoName AS URL, " _
& "PhotoPaths.CurrentPath & 'Thumbs\' & Photos.PhotoName as Thumb " _
& "FROM Photos INNER JOIN PhotoPaths ON Photos.PhotoPathID = PhotoPaths.PhotoPathID WHERE "
SortOrder = " ORDER BY ProjectID, SurveyID, SampleID, Photo_ID"
'set scope for export
WhereClause = "(((Photos.Latitude) Between -90 And 90) AND ((Photos.Longitude) Between -180 And 180) AND ((Photos.Latitude)<>0) AND ((Photos.Longitude)<>0)) AND " & WhereClause
SQL = FixedFields & WhereClause & SortOrder & ";"
'Export data as a delimited list
FileName = ExportCSV(FileName, SQL)
Call OpenBrowser(FileName)
End Sub
下一段代码实际上写出了分隔的文本文件(html 只有标签而不是管道)。在这种情况下,竖线或竖线用于分隔值而不是逗号,因为逗号可能出现在数据中。该代码计算出自己有多少列,并将标题放在顶部。
Public Function ExportCSV(FileAddress As Variant, SQL As String) As String
If Not gDeveloping Then On Error GoTo procerr
PushStack ("mfiles.ExportCSV")
'Exports a csv file
If Nz(FileAddress, "") = "" Then
ExportCSV = "Failed"
Exit Function
End If
'Create text file:
Dim webfile As Object, w
Set webfile = CreateObject("Scripting.FileSystemObject")
Set w = webfile.CreateTextFile(FileAddress, True)
Dim D As Database, R As Recordset, NumberOfFields As Long, Out As String, i As Long
Set D = CurrentDb()
Set R = D.OpenRecordset(SQL, dbOpenSnapshot)
If R.RecordCount > 0 Then
With R
NumberOfFields = .Fields.Count - 1
'Field headings
For i = 0 To NumberOfFields
If i = 0 Then
Out = .Fields(i).Name
Else
Out = Out & "|" & .Fields(i).Name
End If
Next
w.writeline Out
'Field data
Do Until .EOF
For i = 0 To NumberOfFields
If i = 0 Then
Out = .Fields(i)
Else
Out = Out & "|" & .Fields(i)
End If
Next i
w.writeline Out
.MoveNext
Loop
End With
End If
Set R = Nothing
Set D = Nothing
ExportCSV = FileAddress
exitproc:
PopStack
Exit Function
procerr:
Call NewErrorLog(Err.Number, Err.Description, gCurrentProc, FileAddress & ", " & SQL)
Resume exitproc
End Function
下面是来自 openbrowser 函数的 sn-p。该函数的其余部分用于确定网络浏览器的位置,因为这取决于 Windows 的版本以及浏览器是 32 位还是 64 位。
'Set up preferred browser
If Right(BrowserPath, 9) = "Opera.exe" Then
FilePrefix = "file://localhost/"
ElseIf Right(BrowserPath, 11) = "Firefox.exe" Then
FilePrefix = "file:///"
Else
FilePrefix = ""
End If
'Show report
Instruction = BrowserPath & " " & FilePrefix & WebpageName
TaskSuccessID = Shell(Instruction, vbMaximizedFocus)
此示例包含创建 html 报告所需的大约 90% 的代码,该报告的范围由调用它的表单设置。希望这能让某人克服困难。
【讨论】:
以上是关于实现 Access 2007“HTML 报告”的更好方法的主要内容,如果未能解决你的问题,请参考以下文章
要在 Access 2007 中打开的 Access 2013 文件
Access 2007 与 Sharepoint 2007 任务列表的集成
同时运行 Access 2003 和 2007 是不是安全?