Placing letters under underlined text in XSL-FO us

2019-07-02 22:17发布

问题:

I have a project that requires me to place a ID string under some underlined text in a passage of text.

Here is an example using an inline SVG object with a gray border to show the layout:

I can get close using an inline element with a baseline-shift and then use SVG to render the text. However this has the disadvantage (I think) that I have to manually put in the width of the SVG in pixels, which seems very complicated for such a simple layout.

Here is the XSL-FO markup for this:

<fo:block>
Normal text
<fo:inline baseline-shift="-100%">
    <fo:instream-foreign-object text-align="center" display-align="center" border="solid silver 1px">
        <svg xmlns="http://www.w3.org/2000/svg" height="25" width="120" viewport="0 0 120 25">
            <text x="60" y="10" fill="black" text-anchor="middle" text-decoration="underline" font-size="12pt">underlined text with id</text>
            <text x="60" y="25" fill="black" text-anchor="middle" font-size="12pt">123</text>
        </svg>
    </fo:instream-foreign-object>
</fo:inline>
normal text.
</fo:block>

So my question is: Can I perform this layout in Apache FOP XSL-FO without using instream-foreign-object and SVG? If I can not, is there some way to not have to put the width in the SVG in pixels? Or is there some way to calculate how many pixels the SVG will take to render?

I should also note inline-container is not supported in Apache FOP.

https://xmlgraphics.apache.org/fop/compliance.html

Thanks in advance! - Dan

回答1:

Here is a sample done as I suggested with RenderX using the formatting tree.

Format the desired fragments to the intermediate format ... something like this for a single one:

    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
        <fo:layout-master-set>
            <fo:simple-page-master margin="0mm" master-name="MASTERsite1" page-width="214mm" page-height="29pt">
                <fo:region-body margin="0mm"/>
            </fo:simple-page-master>
        </fo:layout-master-set>    
        <fo:page-sequence master-reference="MASTERsite1">
            <fo:flow flow-name="xsl-region-body">
                <fo:table>
                    <fo:table-body>
                        <fo:table-row>
                            <fo:table-cell><fo:block text-decoration="underline" text-align="center">This is Underlined Text with ID</fo:block></fo:table-cell>
                        </fo:table-row>
                        <fo:table-row>
                            <fo:table-cell><fo:block text-align="center">1234567</fo:block></fo:table-cell>
                        </fo:table-row>
                    </fo:table-body>  
                </fo:table>
            </fo:flow>
        </fo:page-sequence> 
    </fo:root>

The output of that would be this:

    <xep:document xmlns:xep="http://www.renderx.com/XEP/xep" producer="XEP 4.19 build 20110414" creator="Unknown" author="Unknown" title="Untitled">
        <xep:page width="162708" height="29000" page-number="1" page-id="1">
    <xep:word-spacing value="0"/>
    <xep:letter-spacing value="0"/>
    <xep:font-stretch value="1.0"/>
    <xep:font family="Helvetica" weight="400" style="normal" variant="normal" size="12000"/>
    <xep:gray-color gray="0.0"/>
    <xep:text value="This is Underlined Text with ID" x="0" y="18734" width="162708"/>
    <xep:line x-from="0" x-till="162708" y-from="17534" y-till="17534" thickness="600" style="solid"/>
    <xep:text value="1234567" x="58002" y="4334" width="46704"/>
    </xep:page>
    </xep:document>

Where you would modify the result to change the page width, but it's right in the text as the width of the text element of concern, that is change:

 <xep:page width="606614" height="29000" page-number="1" page-id="1">

so the width is from the text line of concern, programmatically pick up the x-till from xep:line or the xep:text line (changing as above). Note, this is exactly equivalent to your SVG example except you have the number programmatically to access right inside this file.

last, using this "file" as an image, one would then use:

 <fo:external-graphic src="test19.xep" content-type="application/xepout" alignment-baseline="central"/>

Now, while you say look at all those steps, this is a solution and all of the above could be automated into a single process chain. First loop through and format all of the objects of concern and make little files from them, then a second pass would instead of formatting those fragments, would use them as images.

Note: The line spacing shown in the attached image of the result cannot be done with FOP (I believe), I think that is a limitation of FOP.

Note #2: I am not a FOP expert and I know nothing of it's implementation, specifically using the area tree as an image in a document. If FOP is a must, I would suggest looking into it. You could just as easily convert the area tree to SVGs and use them as you would be able to use all their dimensions or better just read the area tree into the second transform and generate instream-foreign-object SVGs from it right inline.