如何解决XSL-FO生成PDF时跨列表头的PDF-UA合规验证问题?
解决XSL-FO生成PDF-UA合规表格跨列表头验证问题
我们使用XSL-FO生成符合PDF-UA标准的PDF,采用veraPDF进行合规性验证。当表格表头存在横向跨列单元格时,验证工具触发了规则7.5-1的报错:
"未使用Headers属性和ID组织的表格中,TH单元格未包含Scope属性"
我们原本的处理方式是为每个表头单元格设置ID,在表格主体单元格中通过rx:header-idref(renderX-XEP特有方案)引用对应表头ID,但当表头存在跨列时,部分主体单元格找不到对应的表头ID(例如第一行主体单元格的第二个单元格“R ≤ 10 (hb + hw)”),导致验证失败。
补充说明
源XML
<table> <tgroup cols="4" align="left"> <colspec colnum="1" colwidth="28.1*" colname="col1"/> <colspec colnum="2" colwidth="34.3*" colname="col2"/> <colspec colnum="3" colwidth="20*" colname="col3"/> <colspec colnum="4" colwidth="17.7*" colname="col4"/> <thead valign="bottom"> <row rowsep="1"> <entry namest="col1" nameend="col2" valign="top" align="center" colname="col1" rotate="0" morerows="1" colsep="1"> <Al>afstand</Al> </entry> <entry namest="col3" nameend="col4" valign="top" align="left" colname="col3" rotate="0" colsep="1"> <Al>minimum aantal metingen <i>N</i></Al> </entry> </row> <row rowsep="1"> <entry valign="top" align="left" colname="col3" rotate="0" colsep="1"> <Al>zonder afscherming</Al> </entry> <entry valign="top" align="left" colname="col4" rotate="0" colsep="1"> <Al>met afscherming</Al> </entry> </row> </thead> <tbody valign="top"> <row rowsep="1"> <entry valign="top" align="left" colname="col1" rotate="0" colsep="1"/> <entry valign="top" align="left" colname="col2" rotate="0" colsep="1"> <Al><i>R</i> ≤ 10 (<i>h<sub>b</sub></i> + <i>h<sub>w</sub></i>)</Al> </entry> <entry valign="top" align="left" colname="col3" rotate="0" colsep="1"> <Al>1</Al> </entry> <entry valign="top" align="left" colname="col4" rotate="0" colsep="1"> <Al>1</Al> </entry> </row> <row rowsep="1"> <entry valign="top" align="left" colname="col1" rotate="0" colsep="1"> <Al>10 (<i>h<sub>b</sub></i> + <i>h<sub>w</sub></i>) <</Al> </entry> <entry valign="top" align="left" colname="col2" rotate="0" colsep="1"> <Al><i>R</i> ≤ 20 (<i>h<sub>b</sub></i> + <i>h<sub>w</sub></i>)</Al> </entry> <entry valign="top" align="left" colname="col3" rotate="0" colsep="1"> <Al>1</Al> </entry> <entry valign="top" align="left" colname="col4" rotate="0" colsep="1"> <Al>2</Al> </entry> </row> <row rowsep="1"> <entry valign="top" align="left" colname="col1" rotate="0" colsep="1"> <Al>20 (<i>h<sub>b</sub></i> + <i>h<sub>w</sub></i>) <</Al> </entry> <entry valign="top" align="left" colname="col2" rotate="0" colsep="1"> <Al> <i>R</i> </Al> </entry> <entry valign="top" align="left" colname="col3" rotate="0" colsep="1"> <Al>2</Al> </entry> <entry valign="top" align="left" colname="col4" rotate="0" colsep="1"> <Al>3</Al> </entry> </row> </tbody> </tgroup> </table>
当前XSLT代码片段
<xsl:template match="row/entry" mode="content"> <xsl:param name="inThead" as="xs:boolean" tunnel="yes"/> <fo:table-cell> <xsl:choose> <xsl:when test="$inThead"> <!-- In de thead delen we aleeen id's uit aan die entries die als eerste voorkomen met hun betreffende colname, zodat id uniek is. --> <xsl:variable name="colname" select="@colname"/> <xsl:if test="not(parent::row/preceding-sibling::row/entry[@colname=$colname])"> <xsl:attribute name="id" select="@colname"/> </xsl:if> </xsl:when> <xsl:otherwise> <xsl:attribute name="rx:header-idref" select="@colname"/> </xsl:otherwise> </xsl:choose> <!-- here some other logic --> </fo:table-cell> </xsl:template>
解决方案
1. 为表头单元格添加scope属性
PDF-UA要求表头单元格必须明确其覆盖范围:跨列的表头单元格设置scope="colgroup",普通单列表头设置scope="col",这能直接解决规则7.5-1的报错。
2. 调整XSLT逻辑,处理跨列的ID关联
修改原有的XSLT代码,让跨列表头的ID能被所有覆盖列的主体单元格引用,同时确保每个表头单元格都有唯一ID:
<xsl:template match="row/entry" mode="content"> <xsl:param name="inThead" as="xs:boolean" tunnel="yes"/> <fo:table-cell> <xsl:if test="$inThead"> <xsl:variable name="colname" select="@colname"/> <!-- 为所有表头单元格分配唯一ID --> <xsl:attribute name="id" select="$colname"/> <!-- 根据是否跨列设置scope属性 --> <xsl:choose> <xsl:when test="@namest and @nameend"> <xsl:attribute name="scope">colgroup</xsl:attribute> </xsl:when> <xsl:otherwise> <xsl:attribute name="scope">col</xsl:attribute> </xsl:otherwise> </xsl:choose> </xsl:if> <xsl:if test="not($inThead)"> <xsl:variable name="currentCol" select="@colname"/> <!-- 找到当前列对应的表头单元格:包括直接匹配colname,或被跨列表头覆盖的情况 --> <xsl:variable name="headerEntry" select="ancestor::table/tgroup/thead/row/entry[ @colname = $currentCol or ( @namest and @nameend and $currentCol = ancestor::tgroup/colspec[ @colnum >= number(substring-after(current()/@namest, 'col')) and @colnum <= number(substring-after(current()/@nameend, 'col')) ]/@colname ) ]"/> <!-- 引用找到的表头ID --> <xsl:if test="$headerEntry"> <xsl:attribute name="rx:header-idref" select="$headerEntry/@colname"/> </xsl:if> </xsl:if> <!-- 保留原有其他逻辑 --> </fo:table-cell> </xsl:template>
3. 验证调整后的效果
修改后重新生成PDF,用veraPDF验证:
- 所有表头单元格都有
scope属性,解决规则7.5-1的报错 - 跨列覆盖的主体单元格能正确引用到对应的表头ID,确保无障碍关联正确
内容的提问来源于stack exchange,提问作者Siebe Jongebloed
相关产品推荐
相关产品推荐

