在现代Web开发中,PDF文件因其格式的一致性和跨平台特性而广受欢迎。开发者经常需要将网页内容转换为PDF格式,或者在生成PDF时自动添加一些修改。本文将展示一个在ASP.NET环境中使用.NET和XSLT技巧以及PD4ML PDF库来实现这一任务的简单示例。
ASP.NET非常适合创建复杂的页面,但这些控件和其它元素与最终呈现给客户端的xHTML标记几乎没有共同之处。因此,首先要做的是将这些标记“暴露”出来。标记是通过页面生命周期的“Render”方法创建的,所以需要重写这个方法。
protected override void Render(HtmlTextWriter output)
{
// 创建字符串和Html写入器以复制创建的HTML标记
StringWriter writer = new StringWriter();
HtmlTextWriter htmlWriter = new HtmlTextWriter(writer);
// 利用“假”HtmlTextWriter创建HTML标记
base.Render(htmlWriter);
// 将标记复制到字符串并保存到磁盘
string htmlMarkup = writer.ToString();
StreamWriter XMLwriter = new StreamWriter(Server.MapPath("Htmloutput.xml"));
XMLwriter.Write(htmlMarkup);
XMLwriter.Close();
// 创建实际的HTML标记以供显示
output.Write(htmlMarkup);
}
现在需要准备XSLT文件。ASP.NET生成有效的xHTML标记,所以只需要根据需要进行修改,但可能还会遇到一些问题:
首先,不要忘记xHTML标记使用默认的xmlns=http://www.w3.org/1999/xhtml命名空间,所以需要在XSLT文件中创建一些前缀,以便访问节点。这就是为什么在XSLT文件中添加xmlns:xhtml=http://www.w3.org/1999/xhtml字符串,并添加xhtml到“exclude-result-prefixes”中,以从结果文档中移除它。
其次,现在可以进行转换,但还有一个问题:输出文档中有很多xmlns=""节点。为了摆脱它们,添加xmlns=http://www.w3.org/1999/xhtml到XSLT文件的命名空间声明中。
第三,HTML页面包含纯文本,这在XML中是不允许的,因此XSLT不会处理它。为了摆脱文本节点,在XSLT样式表中放入
<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns="http://www.w3.org/1999/xhtml" exclude-result-prefixes="msxsl xhtml">
</xsl:stylesheet>
这是最终目标。所要做的就是执行XSL转换并创建PDF文件。将使用PD4ML HTML到PDF转换库,因为它可以在不同的编程语言中使用,如Java、PHP、Ruby等。将使用MemoryStream,因为不希望将任何中间数据保存到硬盘上。
protected void MakePDFButton_Click(object sender, EventArgs e)
{
// 执行XSL转换
string XSLTFile = Server.MapPath("XSLTFile.xslt");
string XMLFile = Server.MapPath("Htmloutput.xml");
// 允许xHTML标记中的DTD
XmlReaderSettings settings = new XmlReaderSettings();
settings.ProhibitDtd = false;
XmlReader reader = XmlReader.Create(XMLFile, settings);
// 转换初始HTML标记并输出到MemoryStream
XslCompiledTransform XSLTransform = new XslCompiledTransform();
XSLTransform.Load(XSLTFile);
Stream memoryStream = new MemoryStream();
XSLTransform.Transform(reader, null, memoryStream);
// 刷新流并将光标定位在流数据的开头
memoryStream.Flush();
memoryStream.Position = 0;
reader.Close();
// 在页面上显示标记
StreamReader streamReader = new StreamReader(memoryStream);
string output = streamReader.ReadToEnd();
HTMLoutput.Text = Server.HtmlEncode(output);
// 将结果HTML页面转换为PDF
PD4ML PDFcreator = new PD4ML();
PDFcreator.PageSize = PD4Constants.A4;
PDFcreator.DocumentTitle = "The result PDF file";
string path = Server.MapPath("Output.pdf");
StreamWriter streamWriter = new StreamWriter(path);
memoryStream.Position = 0;
PDFcreator.render(memoryStream as MemoryStream, streamWriter);
// 关闭所有流
streamReader.Close();
streamWriter.Close();
}
就是这样!现在让做一个简短的总结: