如何使用XML中的指数字符通过XSLT将XML转换为PDF

问题描述

我尝试使用xml,xsl和fo在pdf中用指数打印我的公式,以从xml转换为pdf和html。在html中,我没有问题,所有指数均正确显示。可能是因为浏览器将显示所有utf-8字符。但看来apap fop不会这么做。

有没有人可以帮助我,给我小费或告诉我如何做到这一点。我不认为我是第一个需要用fo转换以pdf格式打印指数的人。 我设法打印指数的唯一方法是手动编写内联标签并更改基线偏移以将字符“移动”得更高,但是我认为这不是一个好的解决方案。

以下示例文件显示我的问题。在xsl文件中,我尝试了一些操作

xml文件

<?xml version="1.0" encoding="utf-8"?>
<demo>
    <formulas>
      <formula>0,2 µm + 3 · 10⁻⁶ · a</formula>
      <formula>0,3 µm + 4 · 10⁻³ · b</formula>
      <formula>0,4 µm + 5 · E-6 · c</formula>
      <formula>0,5 µm + 6 · E-3 · d</formula>
    </formulas>
</demo>

xsl文件尝试一下:

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

    <xsl:template match="/demo">
        <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
            <fo:layout-master-set>
                <fo:simple-page-master master-name="master_demo" page-width="21.0cm" page-height="29.7cm" margin-top="0.5cm" margin-bottom="0.25cm" margin-left="2.0cm" margin-right="1.0cm">
                    <fo:region-body region-name="flow_demo" margin-top="0.0cm" margin-bottom="0.85cm" />
                    <fo:region-before extent="4.5cm" />
                    <fo:region-after extent="0.5cm"/>
                </fo:simple-page-master>
            </fo:layout-master-set>

            <fo:page-sequence master-reference="master_demo">
                <fo:flow flow-name="flow_demo">
                    <fo:block-container absolute-position="fixed" top="5.0cm" margin-left="1.0cm">
                        <fo:block>
                            <fo:table>
                                <fo:table-column column-width="6.0cm"/>
                                <fo:table-column column-width="6.0cm"/>
                                <fo:table-column column-width="6.0cm"/>
                                <fo:table-body>
                                    <xsl:for-each select="formulas/formula">
                                        <fo:table-row>
                                            <fo:table-cell>
                                                <fo:block font-size="9pt" font-family="SansSerif" margin-top="0.2cm">
                                                    Test:&#160;<xsl:value-of select="own:GetFormattedFormulaPDF(.)"/>
                                                </fo:block>
                                            </fo:table-cell>
                                            <fo:table-cell>
                                                <fo:block font-size="9pt" font-family="SansSerif" margin-top="0.2cm">
                                                    Test:&#160;<xsl:copy-of select="own:GetFormattedFormulaPDF(.)"></xsl:copy-of>
                                                </fo:block>
                                            </fo:table-cell>
                                            <fo:table-cell>
                                                <fo:block font-size="9pt" font-family="SansSerif" margin-top="0.2cm">
                                                    Test:&#160;&#8254;&#179;&#8254;&#179;&#8315;
                                                </fo:block>
                                            </fo:table-cell>
                                        </fo:table-row>
                                    </xsl:for-each>
                                </fo:table-body>
                            </fo:table>

                            <fo:table margin-top="2.0cm">
                                <fo:table-column column-width="10.0cm"/>
                                <fo:table-body>
                                    <xsl:for-each select="formulas/formula">
                                        <fo:table-row>
                                            <fo:table-cell>
                                                <fo:block font-size="9pt" font-family="SansSerif" margin-top="0.2cm">
                                                    XML-Text:&#160;<xsl:value-of select="."/>
                                                </fo:block>
                                            </fo:table-cell>
                                        </fo:table-row>
                                    </xsl:for-each>
                                </fo:table-body>
                            </fo:table>

                            <fo:table margin-top="2.0cm">
                                <fo:table-column column-width="10.0cm"/>
                                <fo:table-body>
                                    <xsl:for-each select="formulas/formula">
                                        <fo:table-row>
                                            <fo:table-cell>
                                                <fo:block font-size="9pt" font-family="SansSerif" margin-top="0.2cm">
                                                    <xsl:call-template name="mu">
                                                        <xsl:with-param name="formula" select = "." />
                                                    </xsl:call-template>
                                                </fo:block>
                                            </fo:table-cell>
                                        </fo:table-row>
                                    </xsl:for-each>
                                </fo:table-body>
                            </fo:table>

                            <fo:table margin-top="2.0cm">
                                <fo:table-column column-width="10.0cm"/>
                                <fo:table-body>
                                    <xsl:for-each select="formulas/formula">
                                        <fo:table-row>
                                            <fo:table-cell>
                                                <fo:block font-size="9pt" font-family="SansSerif" margin-top="0.2cm">
                                                    Formula with fo-tags:&#160;0,9 µm + 5 · 10<fo:inline font-size="7pt" baseline-shift="40%">–4</fo:inline> · <fo:inline font-style="italic">abc</fo:inline>
                                                </fo:block>
                                            </fo:table-cell>
                                        </fo:table-row>
                                    </xsl:for-each>
                                </fo:table-body>
                            </fo:table>

                        </fo:block>
                    </fo:block-container>
                </fo:flow>
            </fo:page-sequence>

        </fo:root>
    </xsl:template>
    
    <xsl:function name="own:GetFormattedFormulaPDF" as="xs:string">
        <xsl:param name="mu" as="xs:string"></xsl:param>
        <xsl:choose>
            <xsl:when test="contains($mu,'10⁻³')">
                <xsl:variable name="E-3d">
                    10<fo:inline font-size="7pt" baseline-shift="40%">–3</fo:inline> · <fo:inline font-style="italic">d</fo:inline>
                </xsl:variable>
                <xsl:value-of select="concat(substring-before($mu,'10⁻³'),$E-3d)"/>
            </xsl:when>
            <xsl:when test="contains($mu,'10⁻⁶')">
                <xsl:variable name="E-6d">
                    10<fo:inline font-size="7pt" baseline-shift="40%">–6</fo:inline> · <fo:inline font-style="italic">d</fo:inline>
                </xsl:variable>
                <xsl:value-of select="concat(substring-before($mu,'10⁻⁶'),$E-6d)"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:variable name="formel">
                    Formel direkt -> 50<fo:inline font-size="7pt" baseline-shift="40%">–12</fo:inline> · <fo:inline font-style="italic">dx</fo:inline>
                </xsl:variable>
                <xsl:value-of select="$formel"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:function>
    
    <xsl:template name="mu">
        <xsl:param name="formula"></xsl:param>
        <xsl:choose>
            <xsl:when test="contains($formula,'10⁻³')">
                <xsl:variable name="E-3d">
                    Hier Minus 3 -> 10<fo:inline font-size="7pt" baseline-shift="40%">–3</fo:inline> · <fo:inline font-style="italic">d</fo:inline>
                </xsl:variable>
                <xsl:value-of select="concat(substring-before($formula,$E-3d)"/>
            </xsl:when>
            <xsl:when test="contains($formula,'10⁻⁶')">
                <xsl:variable name="E-6d">
                    Hier Minus 6 -> 10<fo:inline font-size="7pt" baseline-shift="40%">–6</fo:inline> · <fo:inline font-style="italic">d</fo:inline>
                </xsl:variable>
                <xsl:value-of select="concat(substring-before($formula,$E-6d)"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:variable name="formel">
                    Formel direkt -> 50<fo:inline font-size="7pt" baseline-shift="40%">–12</fo:inline> · <fo:inline font-style="italic">dx</fo:inline>
                </xsl:variable>
                <xsl:value-of select="$formel"/>
            </xsl:otherwise>
        </xsl:choose>        
    </xsl:template>

</xsl:stylesheet>

解决方法

内联元素可能是更常见的方式。当然,这是我的经验。

因此,我对内嵌标签的唯一建议是使用baseline-shift="super"(请参见https://www.w3.org/TR/xsl11/#baseline-shift),该字体应使用内置在字体中的上标基线。

为何要内联元素,原因有很多:

  • 如果要表示更复杂的公式,最好使用MathML而不是纯文本。 (AFAICT,FOP需要JEuclid才能呈现MathML,但是AH Formatter本身支持MathML 3。)
  • Unicode标准不鼓励使用下标和上标字符。摘自“ Unicode标准版本6.2”(较旧但接近)第15.4节“上标和下标符号”:

通常,Unicode标准不会尝试描述字符在印刷版式中高于或低于基线的位置。因此,对带上标的字母或数字(例如“ 1 st ”或“ DC00 16 ”)进行编码的首选方式是采用格式或标记为富文本格式。

  • 您不能确定每种字体都有上标数字,因此使用标记和样式比期望每个上标数字正确显示还更安全。