You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

XSLT实现表格打印分页控制 避免指定行后出现分页符

DITA表格行打印分页控制失效修复

问题场景

使用XSLT 2.0处理DITA文档打印场景时,需要实现相邻表格行同页显示,禁止行之间出现分页符,具体要求为:内容为“P Type”的跨列表格行后方不能出现分页。
已完成的开发逻辑:

  • 编写XSLT模板匹配目标row节点,为其追加outputclass="keep-with-next"属性
  • 编写打印媒体CSS规则,为携带keep-with-next标识的元素设置page-break-after: avoid属性
    实际渲染异常:目标行后仍然出现分页,规则未生效。

原有问题代码

XSLT脚本

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" exclude-result-prefixes="xs" xmlns:xs=http://www.w3.org/2001/XMLSchema xmlns:xsl=http://www.w3.org/1999/XSL/Transform>

  <xsl:template priority="101" match="row[.//entry[@nameend='c2']/ph]">
    <xsl:call-template name="row-keep-with-next"/>
  </xsl:template>
 
  <xsl:template name="row-keep-with-next">
    <xsl:variable name="row" as="node()">
      <topic class="- topic/tbody "> 
        <xsl:copy >
          <xsl:sequence select="@* except @outputclass"/>
          <xsl:attribute name="outputclass" select="string-join(('keep-with-next', tokenize(@outputclass, '\s+')), ' ')"/>
          <xsl:sequence select="node()"/>
        </xsl:copy>
      </topic>
    </xsl:variable>
   
    <xsl:apply-templates select="$row"/> 
  </xsl:template>
</xsl:stylesheet>

CSS样式

@media print 
    { *[outputclass~="keep-with-next"] { page-break-after: avoid; } 
*[outputclass~="keep-with-previous"] { page-break-before: avoid; } 
*[outputclass~="top-of-page"] { page-break-before: always; } }

测试DITA样例

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE dita
  PUBLIC "-//OASIS//DTD DITA Composite//EN" "dtd/ditabase.dtd">
<dita>
<reference xmlns:ditaarch=http://dita.oasis-open.org/architecture/2005/ id="parameters_top">
<title>Parts</title>
<refbody outputclass="db.sect2">
<section>
<table id="paratable" pgwide="1" outputclass="PTable">
<title outputclass="db.title">Basic Config</title>
<tgroup cols="2" outputclass="ParametersTable">
<colspec colnum="1" colname="c1" colwidth="2*"/>
<colspec colnum="2" colname="c2" colwidth="5*"/>
<thead outputclass="db.thead">
  <row outputclass="db.row">
    <entry outputclass="db.entry">Label</entry>
    <entry outputclass="db.entry">Description</entry>
  </row>
</thead>
<tbody outputclass="db.tbody">
  <row outputclass="db.row">
    <entry outputclass="db.entry" namest="c1" nameend="c2" align="center"><ph outputclass="db.phrase"> P Type </ph></entry>
  </row>
  <row outputclass="db.row">
    <entry outputclass="db.entry"><ph outputclass="db.phrase">Phy</ph></entry>
    <entry outputclass="db.entry"><p outputclass="db.para"><ph outputclass="db.phrase">Select the type of PHY.</ph></p></entry>
  </row>
  <row outputclass="db.row">
    <entry outputclass="db.entry"><ph outputclass="db.phrase">Speed</ph></entry>
    <entry outputclass="db.entry"><p outputclass="db.para">Link speed </p></entry>
  </row>
</tbody>
</tgroup>
</table>
</section>
</refbody>
</reference>
</dita>

失效原因

  1. XSLT逻辑错误
    • 自定义模板中给复制的row节点额外包裹了一层多余的<topic>标签,破坏了DITA表格tgroup > tbody > row > entry的固定层级结构,渲染引擎处理结构异常的表格时会直接忽略节点上的自定义属性
    • 匹配规则过于宽泛,仅判断行内存在跨c2列的ph节点,未校验ph文本内容是否为“P Type”,容易误匹配其他无关行
    • 命名空间声明未加引号,存在XML语法错误
  2. CSS兼容问题
    • 绝大多数DITA渲染流程会将DITA元素的outputclass属性映射为HTML元素的class属性,不会保留原生outputclass属性,原有属性选择器无法匹配到渲染后的DOM节点
    • 浏览器/打印引擎对表格行(tr)的分页属性支持存在兼容问题,仅给tr设置page-break-after不会生效,需要同时给行内单元格设置对应规则,且要兼容W3C标准的break-after属性
  3. 场景适配问题
    • 如果使用DITA OT默认XSL-FO流程生成PDF,CSS规则完全不生效,需要直接给FO节点设置分页属性

修复方案

修正XSLT脚本

移除多余的topic包裹逻辑,修正匹配规则精确命中目标行,修复语法错误:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" exclude-result-prefixes="xs" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <!-- 精确匹配跨c1-c2列、ph文本为P Type的行,优先级高于默认行处理模板 -->
  <xsl:template priority="101" match="row[normalize-space(.//entry[@namest='c1' and @nameend='c2']/ph) = 'P Type']">
    <xsl:copy>
      <!-- 复制原有除outputclass外的所有属性 -->
      <xsl:sequence select="@* except @outputclass"/>
      <!-- 追加keep-with-next标识,保留原有outputclass值 -->
      <xsl:attribute name="outputclass" select="string-join(('keep-with-next', tokenize(@outputclass, '\s+')), ' ')"/>
      <!-- 复制行内所有子节点,不破坏原有结构 -->
      <xsl:sequence select="node()"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

修正CSS打印规则

适配DITA渲染后的DOM结构,兼容多引擎分页规则:

@media print {
  /* 同时兼容原生outputclass属性和映射后的class属性 */
  *[outputclass~="keep-with-next"],
  tr.keep-with-next {
    page-break-after: avoid !important;
    break-after: avoid-page !important;
  }
  /* 给行内最后一个单元格追加规则,适配Webkit、Gecko等不同内核的分页逻辑 */
  *[outputclass~="keep-with-next"] > entry:last-child,
  tr.keep-with-next > td:last-child,
  tr.keep-with-next > th:last-child {
    page-break-after: avoid !important;
    break-after: avoid-page !important;
  }

  *[outputclass~="keep-with-previous"],
  tr.keep-with-previous {
    page-break-before: avoid !important;
    break-before: avoid-page !important;
  }

  *[outputclass~="top-of-page"],
  tr.top-of-page {
    page-break-before: always !important;
    break-before: page !important;
  }
}

补充:如果使用XSL-FO生成PDF,需要额外追加模板给对应fo:table-row设置keep-with-next.within-page="always"属性,CSS规则在FO流程中不生效。


内容的提问来源于stack exchange,提问作者ane435

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 07:42:27