如何用XSLT拼接跨页拆分的XML <par>节点值生成HTML段落?
解决方案:用XSLT合并跨页拆分的OCR段落
这个需求完全可以用XSLT实现,核心思路是按文档顺序遍历所有<par>节点,将属于同一个段落的节点分组合并,判断段落结束的依据是节点文本结尾为句点(可根据实际需求调整判断规则)。
方案1:XSLT 2.0(推荐,分组更简洁)
XSLT 2.0的xsl:for-each-group可以直接按段落结束条件分组,代码如下:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:x="http://www.abbyy.com/FineReader_xml/FineReader10-schema-v1.xml" exclude-result-prefixes="x"> <xsl:output omit-xml-declaration="yes" method="html" indent="yes"/> <xsl:template match="/"> <xsl:for-each-group select="//x:par" group-ending-with="x:par[substring(., string-length(.)) = '.']"> <p> <xsl:value-of select="current-group()" separator=" "/> </p> <xsl:text>
</xsl:text> </xsl:for-each-group> </xsl:template> </xsl:stylesheet>
代码说明:
//x:par:按文档顺序选中所有<par>节点,不管它们在哪个<page>或<block>下group-ending-with="x:par[substring(., string-length(.)) = '.']":将以句点结尾的<par>作为每组的最后一个节点,自动把前面连续的非结尾<par>归为同一组current-group():获取当前组的所有<par>节点,用separator=" "将文本用空格连接
方案2:XSLT 1.0(适配xsltproc等1.0处理器)
XSLT 1.0没有原生分组功能,可通过递归模板实现遍历合并:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:x="http://www.abbyy.com/FineReader_xml/FineReader10-schema-v1.xml" exclude-result-prefixes="x"> <xsl:output omit-xml-declaration="yes" method="html"/> <!-- 匹配根节点,启动递归处理第一个par --> <xsl:template match="/"> <xsl:apply-templates select="(//x:par)[1]" mode="merge"/> </xsl:template> <!-- 递归合并段落的模板 --> <xsl:template match="x:par" mode="merge"> <xsl:variable name="current-par" select="."/> <!-- 收集当前par及后续连续的非结尾par --> <xsl:variable name="merged-text"> <xsl:call-template name="collect-pars"> <xsl:with-param name="start-par" select="$current-par"/> </xsl:call-template> </xsl:variable> <!-- 输出合并后的段落 --> <p><xsl:value-of select="$merged-text"/></p> <xsl:text>
</xsl:text> <!-- 处理下一个未合并的par --> <xsl:apply-templates select="$current-par/following::x:par[count(preceding::x:par) = count($current-par/preceding::x:par) + count($current-par/following::x:par[substring(., string-length(.)) != '.']) + 1]" mode="merge"/> </xsl:template> <!-- 递归收集连续的非结尾par文本 --> <xsl:template name="collect-pars"> <xsl:param name="start-par"/> <xsl:value-of select="$start-par"/> <xsl:if test="substring($start-par, string-length($start-par)) != '.'"> <xsl:text> </xsl:text> <xsl:call-template name="collect-pars"> <xsl:with-param name="start-par" select="$start-par/following::x:par[1]"/> </xsl:call-template> </xsl:if> </xsl:template> </xsl:stylesheet>
代码说明:
- 用
mode="merge"区分普通模板和合并模板,避免冲突 collect-pars模板递归收集当前<par>及后续所有非结尾的<par>文本,直到遇到以句点结尾的节点- 主递归模板输出合并后的段落,再定位到下一个未处理的
<par>继续处理
解决你之前的问题
你之前的代码用following-sibling只能处理同一<block>下的兄弟节点,跨页的<par>不属于兄弟节点,所以无法匹配。上述两种方案用//x:par(2.0)或following::x:par(1.0)遍历所有文档顺序的<par>节点,解决了跨页节点无法访问的问题。
测试示例
输入(你提供的简化文档):
<document xmlns="http://www.abbyy.com/FineReader_xml/FineReader10-schema-v1.xml"> <page> <block> <par>This is a line.</par> <par>This is a line</par> <par>that is split.</par> </block> </page> <page> <block> <par>line split</par> </block> </page> <page> <block> <par>across pages.</par> </block> </page> </document>
输出(与你的理想结果一致):
<p>This is a line.</p> <p>This is a line that is split.</p> <p>line split across pages.</p>
内容的提问来源于stack exchange,提问作者Simon
相关产品推荐
相关产品推荐

