C# iText 7可从HTML访问的PDF:使用display:table时如何避免表标记;

C# iText 7可从HTML访问的PDF:使用display:table时如何避免表标记;,c#,css,itext,itext7,html-to-pdf,C#,Css,Itext,Itext7,Html To Pdf,我正在从事一个ASP.NETMVC项目,该项目将视图转换为PDF。以前使用的是Rotavia,但后来一个新的客户要求是PDF可以访问/508兼容。为了便于布局,以前的开发人员将整个标题部分(徽标、标题、免责声明等)作为一个表,没有th元素(仅td)。我需要将它们转换为div,但保持外观不变。因此,我所做的是将它们设为div,然后在适当的地方使用CSS属性display:table、display:table row组、display:table row和display:table cell。结果

我正在从事一个ASP.NETMVC项目,该项目将视图转换为PDF。以前使用的是Rotavia,但后来一个新的客户要求是PDF可以访问/508兼容。为了便于布局,以前的开发人员将整个标题部分(徽标、标题、免责声明等)作为一个表,没有th元素(仅td)。我需要将它们转换为div,但保持外观不变。因此,我所做的是将它们设为div,然后在适当的地方使用CSS属性display:table、display:table row组、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);
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;
        }
    }
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标记转换为table、tr和td标记。显然,在div上使用display:table的全部目的是避免使用表,但获得相同的布局效果

iText为什么要实现这种行为?有什么办法可以解决吗?如果没有,任何人都可以提供display:table、display:table row group、display:table row和display:table cell的精确CSS等价物,因为iText似乎只看到属性“display:table”并使用table标记。我在继承DefaultTagWorkerFactory的自定义标记工作者工厂中尝试了以下操作,在我的div中添加了一个类“make div”,如下所示:

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);
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;
        }
    }
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);
    }
};
但是,它会抛出一个异常,如“无法隐式地将DivTagWorker转换为DisplayTableRowTagWorker”


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

您似乎已将标记辅助程序替换为
显示:表行
元素,但未将标记辅助程序替换为
显示:表
。当然我不能确定,因为您还没有共享一个示例HTML文件来重现这个问题

在任何情况下,替代标签工人的方法在这里都不是最好的。它只会删除由自定义
显示
CSS属性引起的布局调整,而您的目标是保存布局,但只是更改标记

要保存布局并更改标记,您不应更改创建的标记辅助对象,而应为由这些标记辅助对象创建的
表格
单元格
布局元素设置正确的角色

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

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。

@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);
                    }
                }
            }
        }
    }
}
最后,要使用它:

        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看起来完全相同,并且仍然有正确的标签。非常感谢您的帮助。

Tamer,如果您有此问题的解决方案,请随时通知我。@Fadeel:可以。。。到目前为止看起来不太好though@Fadeel,回答了!非常感谢你。我会尽快试试这个,然后告诉你。谢谢。这真的很有帮助。你也能帮我做这个吗?非常感谢你。