来自HTML的iText 7可访问的PDF:当使用display:table时,如何避免表标记;

我正在开发一个ASP.NET MVC项目,它将视图转换为PDF。 以前使用Rotavia,但新的客户要求是PDF可访问/ 508兼容。 出于布局目的,以前的开发人员有一个完整的标题部分(徽标,标题,免责声明等)作为没有元素的表(只是td)。 我需要将它们转换为div,但看起来保持不变。 所以,我所做的是使它们成为div,然后使用CSS属性,display:table,display:table-row-group,display:table-row,display:table-cell。 它看起来几乎完全相同。

问题是,即使它们现在是div,也使用iText DefaultTagWorkerFactory,如下所示:

ConverterProperties props = new ConverterProperties(); FontProvider fp = new FontProvider(); fp.AddStandardPdfFonts(); props.SetFontProvider(fp); var tagWorkerFactory = new DefaultTagWorkerFactory(); props.SetTagWorkerFactory(tagWorkerFactory); HtmlConverter.ConvertToPdf(html, pdfDoc, props); 

它仍然将Div标签转换为table,tr和td标签。 显然,在div上使用display:table的整个目的是避免使用表但获得相同的布局效果。

为什么iText会实现这种行为,有什么方法吗? 如果没有,任何人都可以提供任何精确的CSS等效显示:table,display:table-row-group,display:table-row,display:table-cell,因为看起来iText只看到属性,“display:table”并使用table-tag。 我在自定义标记工作器工厂中尝试了以下操作,该工厂通过向我的div添加一个类“make-div”来inheritanceDefaultTagWorkerFactory,如下所示:

 public class AccessibilityTagWorkerFactory : DefaultTagWorkerFactory { public override ITagWorker GetCustomTagWorker(IElementNode tag, ProcessorContext context) { var attributes = tag.GetAttributes(); var cssClass = attributes.GetAttribute("class"); if (!string.IsNullOrWhiteSpace(cssClass) && cssClass.Contains("make-div")) { return new DivTagWorker(tag, context); } return null; } } 

但是,它会引发exception,例如“无法将DivTagWorker隐式转换为DisplayTableRowTagWorker”。

所有这一切都让我满怀信心。 任何帮助,将不胜感激。 谢谢。

您似乎已将标记worker替换为display: table-row元素,但未对display: table 。 当然,我无法确定,因为您没有共享示例HTML文件来重现该问题。

无论如何,替代标签工人的方法并不是最好的。 它只会丢弃由自定义display CSS属性引起的布局调整,而您的目标是保存布局,但只需更改标记。

要保存布局并更改标记,不应更改已创建的标记工作程序,而应为由这些标记工作程序创建的TableCell局元素设置正确的角色。

相应的重载标记工作者可能如下所示:

 private static class DivRoleDisplayTableTagWorker extends DisplayTableTagWorker { public DivRoleDisplayTableTagWorker(IElementNode element, ProcessorContext context) { super(element, context); } @Override public void processEnd(IElementNode element, ProcessorContext context) { super.processEnd(element, context); if (getElementResult() instanceof Table) { Table table = (Table) getElementResult(); table.getAccessibilityProperties().setRole(StandardRoles.DIV); for (int i = 0; i < table.getNumberOfRows(); i++) { for (int j = 0; j < table.getNumberOfColumns(); j++) { Cell cell = table.getCell(i, j); if (cell != null) { cell.getAccessibilityProperties().setRole(StandardRoles.DIV); } } } } } } 

您需要做的就是使用display: table替换tag worker for div并使用自定义标记worker。 根据您的文档,您可能会使用不同的条件,但对于简单的情况,自定义标记工作工厂将如下所示:

 ITagWorkerFactory customFactory = new DefaultTagWorkerFactory() { @Override public ITagWorker getCustomTagWorker(IElementNode tag, ProcessorContext context) { if (CssConstants.TABLE.equals(tag.getStyles().get(CssConstants.DISPLAY)) && TagConstants.DIV.equals(tag.name())) { return new DivRoleDisplayTableTagWorker(tag, context); } return super.getCustomTagWorker(tag, context); } }; 

现在你的表格及其单元格将被标记为div。

@AlexeySubach发布了一个非常有用的答案。 它对我来说不是100%有效,但真正帮助我朝着正确的方向发展。 另外,他的回答是Java,我正在使用.NET版的iText。 以下是我最终要做的事情:我将HTML标记保留为表格,因为我有一些表应该是表格而其他表格不应该(它们只是用于布局),我添加了类,“make-table- div“对于我不想成为表格的表格元素。 然后,我创建了这个类:

 public class DivRoleTableTagWorker : TableTagWorker { public DivRoleTableTagWorker(IElementNode element, ProcessorContext context) : base(element, context) { } public override void ProcessEnd(IElementNode element, ProcessorContext context) { base.ProcessEnd(element, context); if (GetElementResult().GetType() == typeof(Table)) { Table table = (Table)GetElementResult(); table.GetAccessibilityProperties().SetRole(StandardRoles.DIV); for (int i = 0; i < table.GetNumberOfRows(); i++) { for (int j = 0; j < table.GetNumberOfColumns(); j++) { Cell cell = table.GetCell(i, j); if (cell != null) { cell.GetAccessibilityProperties().SetRole(StandardRoles.DIV); } } } } } } 

 public class AccessibilityTagWorkerFactory : DefaultTagWorkerFactory { public override ITagWorker GetCustomTagWorker(IElementNode tag, ProcessorContext context) { bool hasClass = false; foreach (var attribute in tag.GetAttributes()) { if (attribute.GetKey() == "class") { hasClass = true; } } if (hasClass && tag.GetAttribute(AttributeConstants.CLASS).Contains("make-h1")) { return new HRoleSpanTagWorker(tag, context, StandardRoles.H1); } if (hasClass && tag.GetAttribute(AttributeConstants.CLASS).Contains("make-h2")) { return new HRoleSpanTagWorker(tag, context, StandardRoles.H2); } if (hasClass && tag.GetAttribute(AttributeConstants.CLASS).Contains("make-table-div")) { return new DivRoleTableTagWorker(tag, context); } return base.GetCustomTagWorker(tag, context); } } 

最后,使用它:

  ConverterProperties props = new ConverterProperties(); FontProvider fp = new FontProvider(); fp.AddStandardPdfFonts(); props.SetFontProvider(fp); DefaultTagWorkerFactory tagWorkerFactory = new AccessibilityTagWorkerFactory(); props.SetTagWorkerFactory(tagWorkerFactory); HtmlConverter.ConvertToPdf(html, pdfDoc, props); pdfDoc.Close(); 

通过这种方式,我能够保持PDF看起来完全相同,并且仍然具有正确的标签。 非常感谢你的帮助。