【问题标题】:iText 7 accessible PDFs from HTML: how do I avoid table tag when using display: table;来自 HTML 的 iText 7 可访问 PDF:使用 display:table 时如何避免 table 标签;
【发布时间】:2018-07-13 08:35:09
【问题描述】:

我正在开发一个将视图转换为 PDF 的 ASP.NET MVC 项目。以前,使用的是 Rotavia,但新的客户要求是 PDF 可访问/符合 508。出于布局目的,以前的开发人员将整个标题部分(徽标、标题、免责声明等)作为没有 th 元素的表格(仅 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 等效项 display:table、display:table-row-group、display:table-row 和 display:table-cell,因为 iText 似乎只看到属性“display:table”并使用表标签。我在继承 DefaultTagWorkerFactory 的自定义标签工作者工厂中尝试了以下操作,方法是向我的 div 添加一个类“make-div”,如下所示:

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;
        }
    }

但是,它会引发类似“无法将 DivTagWorker 隐式转换为 DisplayTableRowTagWorker”的异常。

我对这一切都束手无策。任何帮助,将不胜感激。谢谢。

【问题讨论】:

  • 驯兽师,如果您有解决此问题的方法,请随时通知我。
  • @Fadeel : 会的...不过目前看起来不太好
  • @Fadeel,有人回答了!

标签: c# css itext itext7 html-to-pdf


【解决方案1】:

您似乎已经用标签工作者替换了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);
                    }
                }
            }
        }
    }
}

您需要做的就是用您的自定义标签工作程序将div 替换为display: table。根据您的文档,您可能会使用不同的条件,但对于一个简单的情况,自定义标签工人工厂将如下所示:

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。

【讨论】:

【解决方案2】:

@AlexeySubach 发布了一个非常有用的答案。它对我来说并不是 100% 有效,但确实帮助我朝着正确的方向前进。此外,他的答案是用 Java 编写的,而我正在使用 iText 的 .NET 版本。这是我最终做的事情: 我将 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 看起来完全一样,并且仍然具有正确的标签。非常感谢您的帮助。

【讨论】:

    猜你喜欢
    • 2018-12-09
    • 2017-07-31
    • 1970-01-01
    • 1970-01-01
    • 2021-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-01
    相关资源
    最近更新 更多