65.9K
CodeProject 正在变化。 阅读更多。
Home

在 ASP.NET 中为 PDF 转换目的执行 xHTML 到 xHTML 转换。

starIconstarIconemptyStarIconemptyStarIconemptyStarIcon

2.00/5 (1投票)

2011年3月1日

CPOL

3分钟阅读

viewsIcon

28548

downloadIcon

540

本文讨论了用于 PDF 输出目的的动态 xHtml 到 xHtml XSL 转换。

引言

将 HTML 页面转换为不同格式,尤其是 PDF,已成为 Web 开发人员广泛采用的常规操作。这个过程本身相当直接,因为 Web 上有大量的 PDF 开发库和服务。但是,有一天,您可能不仅需要制作页面的 PDF 副本,还需要自动对生成的 PDF 输出进行一些修改(例如,您可能想访问页面上的 SVG 数据)。在本文中,我将演示一个在 ASP.NET 中使用一些 .NET 和 XSL 技巧以及 PD4ML PDF 库来完成此任务的简单示例。

步骤 1:搜索 xHTML 标记

ASP.NET 非常适合轻松创建复杂的页面。但是,所有这些控件和其他东西与渲染并发送到客户端的 xHTML 标记几乎没有关系。因此,我们要做的第一件事就是以某种方式将其揭示出来。标记是借助生命周期的“Render”方法创建的,所以我们需要重写该方法。

protected override void Render(HtmlTextWriter output)
{
   //Creating String and Html writers to copy the created HTML markup
   StringWriter writer = new StringWriter();
   HtmlTextWriter htmlWriter = new HtmlTextWriter(writer);
   //Creating HTML markup with the help of our "fake" HTmlTextWriter
   base.Render(htmlWriter);
   //Coping the markup to the string and saving it to the disk
   string htmlMarkup = writer.ToString();
   StreamWriter XMLwriter = new StreamWriter(Server.MapPath("Htmloutput.xml"));
   XMLwriter.Write(htmlMarkup);
   XMLwriter.Close();
   //Creating actual HTML markup for display
   output.Write(htmlMarkup);
}

步骤 2:准备进行 XSL 转换

现在我们需要准备我们的 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 样式表中放置 <xsl:template match="xhtml:body//text()"> 模板。
    <?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">
    <!--the rest of the xsl file --!>

步骤 3:创建 PDF 文件

这就是我们达到最终目标的地方。我们所要做的就是执行 XSL 转换并创建 PDF 文件。我将使用 – PD4ML HTML to PDF 转换库,因为它可以在 Java、PHP、Ruby 等不同的编程语言中使用。我将使用 MemoryStream,因为我不想将任何中间数据保存到硬盘。

protected void MakePDFButton_Click(object sender, EventArgs e)
{
   //Doing XSL transformation
   string XSLTFile = Server.MapPath("XSLTFile.xslt");
   string XMLFile = Server.MapPath("HTMLoutput.xml");
   // Allowing DTD in our xHTML markup
   XmlReaderSettings settings = new XmlReaderSettings();
   settings.ProhibitDtd = false;
   XmlReader reader = XmlReader.Create(XMLFile, settings);
   //Transforming the initial HTML markup and outputting it to MemoryStream
   //object instance for further PDF conversion
   XslCompiledTransform XSLTransform = new XslCompiledTransform();
   XSLTransform.Load(XSLTFile);
   Stream memoryStream = new MemoryStream();
   XSLTransform.Transform(reader, null, memoryStream);
   //Flushing the stream and positioning the cursor at the beginning
   //of the data in the stream.
   memoryStream.Flush();
   memoryStream.Position=0;
   reader.Close();

   //Showing the markup on the page
   StreamReader streamReader=new StreamReader(memoryStream);
   string output=streamReader.ReadToEnd();
   HTMLoutput.Text = Server.HtmlEncode(output);

   //Converting result HTML page to 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);
   //Closing all the streams
   streamReader.Close();
   streamWriter.Close();
}

结论

就是这样!现在让我们来一个简短的总结。

  • 使用重写的“Render”方法来操作和获取 xHTML 标记。
  • 使用自定义 XML 命名空间前缀来访问未加前缀的 xHTML 节点。
  • 使用一点 xslt“xmlns=http://www.w3.org/1999/xhtml”技巧来摆脱大量的 xmlns="" 节点。
  • 如果您需要摆脱未被任何元素包装的纯文本,请使用 <xsl:template match="xhtml:body//text()">

我希望 Visual Studio 开发人员“想当然”的有效 xHTML 标记与上面描述的几个简单技巧相结合,将为您提供无数种操作文档数据的可能性。

历史

  • 2011 年 3 月 1 日:初始帖子
© . All rights reserved.