XSLT 输出纯文本表

标签 xslt plaintext xmltable

我正在使用 XSL 模板将 XHTML/hResume 文档转换为纯文本,但我在表格布局方面遇到了问题(不,不是布局表格)。目前我有以下内容,使用优秀的 Dave Pawson 的 padding template :

<variable name="newline" select="'&#10;'"/>
<template match="xhtml:table">
    <variable name="maxWidth">
        <for-each select="xhtml:tr/xhtml:th | xhtml:tr/xhtml:td">
            <sort select="string-length(child::text()|child::node())" order="descending" data-type="number"/>
            <if test="position() = 1">
                <value-of select="string-length(child::text()|child::node())"/>
            </if>
        </for-each>
    </variable>
    <for-each select="xhtml:tr">
        <for-each select="xhtml:th|xhtml:td">
            <variable name="string">
                <for-each select="child::text()|child::node()">
                    <value-of select="."/>
                </for-each>
            </variable>
            <value-of select="$string"/>
            <call-template name="append-pad">
                <with-param name="length" select="$maxWidth - string-length($string)"/>
            </call-template>
            <text>&#32;</text>
        </for-each>
        <value-of select="$newline"/>
    </for-each>
    <value-of select="$newline"/>
</template>

这会产生等宽的列,但我想通过以下几种方式对其进行改进:
  • 查找并使用每列的最大宽度。为此,有必要存储灵活数量的值。在简单的情况下,我可以更改 maxWidth 来执行此操作,但是您如何处理跨列?
  • 将跨列的内容居中。

  • 有没有模板可以做这样的事情?

    最佳答案

    带有“全局”(对于表格中的每个单元格)$maxWith你可以像这个样式表一样处理 colspans(保留你自己的逻辑):

    <stylesheet version="1.0" xmlns="http://www.w3.org/1999/XSL/Transform" xmlns:xhtml="http://www.w3.org/1999/xhtml">
        <output method="text"/>
        <variable name="newline" select="'&#10;'"/>
        <template match="xhtml:table">
            <variable name="maxWidth">
                <for-each select="xhtml:tr/xhtml:th | xhtml:tr/xhtml:td">
                    <sort select="string-length(child::text()|child::node())" order="descending" data-type="number"/>
                    <if test="position() = 1">
                        <value-of select="string-length(child::text()|child::node())"/>
                    </if>
                </for-each>
            </variable>
            <for-each select="xhtml:tr">
                <for-each select="xhtml:th|xhtml:td">
                    <variable name="string">
                        <for-each select="child::text()|child::node()">
                            <value-of select="."/>
                        </for-each>
                    </variable>
                    <variable name="padding">
                        <choose>
                            <when test="@colspan">
                                <value-of select="$maxWidth * @colspan + @colspan - 1 - string-length($string)"/>
                            </when>
                            <otherwise>
                                <value-of select="$maxWidth - string-length($string)"/>
                            </otherwise>
                        </choose>
                    </variable>
                    <value-of select="$string"/>
                    <call-template name="append-pad">
                        <with-param name="length" select="$padding"/>
                    </call-template>
                    <text>&#32;</text>
                </for-each>
                <value-of select="$newline"/>
            </for-each>
            <value-of select="$newline"/>
        </template>
        <template name="append-pad">
            <param name="length" select="0"/>
            <if test="$length != 0">
                <value-of select="'&#32;'"/>
                <call-template name="append-pad">
                    <with-param name="length" select="$length - 1"/>
                </call-template>
            </if>
        </template>
    </stylesheet>
    

    输入:
    <table xmlns="http://www.w3.org/1999/xhtml">
        <tr>
            <th>First</th>
            <th>Second</th>
            <th>Third</th>
        </tr>
        <tr>
            <td>One</td>
            <td>Two</td>
            <td>Three</td>
        </tr>
        <tr>
            <td colspan="2">Uno</td>
            <td>Tres</td>
        </tr>
    </table>
    

    输出:
    First  Second Third  
    One    Two    Three  
    Uno           Tres   
    

    编辑 :为了使用 colspan 将单元格居中,请使用此样式表(现在使用我自己的逻辑):
    <stylesheet version="1.0" xmlns="http://www.w3.org/1999/XSL/Transform" xmlns:xhtml="http://www.w3.org/1999/xhtml">
        <output method="text"/>
        <variable name="newline" select="'&#10;'"/>
        <template match="xhtml:table">
            <apply-templates>
                <with-param name="maxWidth">
                    <for-each select="xhtml:tr/xhtml:th | xhtml:tr/xhtml:td">
                        <sort select="string-length(.)" order="descending" data-type="number"/>
                        <if test="position() = 1">
                            <value-of select="string-length(.)"/>
                        </if>
                    </for-each>
                </with-param>
            </apply-templates>
            <value-of select="$newline"/>
        </template>
        <template match="xhtml:tr">
            <param name="maxWidth"/>
            <apply-templates>
                <with-param name="maxWidth" select="$maxWidth"/>
            </apply-templates>
            <value-of select="$newline"/>
        </template>
        <template match="xhtml:th|xhtml:td">
            <param name="maxWidth"/>
            <variable name="string">
                <for-each select="child::text()|child::node()">
                    <value-of select="."/>
                </for-each>
            </variable>
            <variable name="padding">
                <choose>
                    <when test="@colspan">
                        <value-of select="($maxWidth * @colspan + @colspan - 1 - string-length($string)) div 2"/>
                    </when>
                    <otherwise>
                        <value-of select="$maxWidth - string-length($string)"/>
                    </otherwise>
                </choose>
            </variable>
            <if test="@colspan">
                <call-template name="append-pad">
                    <with-param name="length" select="floor($padding)"/>
                </call-template>
            </if>
            <value-of select="$string"/>
            <call-template name="append-pad">
                <with-param name="length" select="ceiling($padding)"/>
            </call-template>
            <text>&#32;</text>
        </template>
        <template name="append-pad">
            <param name="length" select="0"/>
            <if test="$length != 0">
                <value-of select="'&#32;'"/>
                <call-template name="append-pad">
                    <with-param name="length" select="$length - 1"/>
                </call-template>
            </if>
        </template>
    </stylesheet>
    

    输出:
    First  Second Third  
    One    Two    Three  
         Uno      Tres   
    

    关于XSLT 输出纯文本表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3505022/

    相关文章:

    c# - 一个umbraco 上的多个网站,需要xslt 宏吗?

    javascript - 如何为特定节点编写条件 xpath 选择?

    php - 来自服务器的纯文本响应 (PHP/MySQL)

    regex - 如何使用 Perl 从纯文本中提取 URL?

    xml - PLSQL XMLTable XPath 获取最深深度的所有标签

    xml - 在 Postgres 中使用 xmltable

    html - 如何在 XSL 生成的文件中包含正确的 XML/HTML 定义?

    xml - 所选元素的 XSLT 位置

    passwords - 为什么纯文本密码不好?我如何让老板相信他珍视的网站正处于危险之中?

    xslt - 使用 XSLT 1.0 将元素连接行和列名称的平面 XML 表数据转换为嵌套的 XML