xsl or xsl:fo interaction of two templates during

2019-07-26 16:36发布

问题:

In transforming a large XML text corpus (to a PDF, XSL 3.0, XSL:FO) I am running into a template problem with controlling what ultimately appears in the body of the output and what appears in the margin, resulting from one element. I'm not sure if this is an xsl or xsl:fo issue.

The problem is with the output of element <add type="margin_gloss">, processed by templates <xsl:template match="seg[@type='dep_event']">and <xsl:template match="add[@type='margin_gloss']"> in the example below. I expect the contents of <add type="margin_gloss"> to only appear in the margin; but it's persisting in the body as well.

This xml markup:

<corpus>
  <deposition>
    <text>
        <deposition-title>Some foo title</deposition-title>
        <seg type="dep_event"> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam vitae venenatis
            ante. Suspendisse posuere velit non nisi tincidunt, commodo faucibus neque volutpat.
            Integer <add type="margin_gloss">This is a <foreign>foo</foreign> ma<supplied reason="added">rgin</supplied> note</add> 
            posuere laoreet sem eu scelerisque. Vestibulum purus risus, semper
            vitae suscipit non, mal<supplied reason="added">esuada</supplied> ut massa. Sed et auctor erat.</seg>
        <seg type="dep_event"> Suspendisse eu urna sed purus mattis placerat. Vestibulum <foreign>some English</foreign> scelerisque
            lectus, in lobortis tortor fa<supplied reason="added">cilisis</supplied> eu. Donec mollis pulvinar varius. Nam eget
            euismod ipsum, ac suscipit nunc. Sed volutpat non felis id varius. </seg>
    </text>
</deposition>
</corpus>

Processed by this xsl:fo:

<xsl:stylesheet 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:fo="http://www.w3.org/1999/XSL/Format" 
xmlns:xd="http://www.pnp-software.com/XSLTdoc"
version="3.0">

<xsl:template match="/">
    <fo:root>
        <fo:layout-master-set>
            <fo:simple-page-master 
                master-name="page-recto"
                page-height="29.7cm"  page-width="21cm"
                margin-top="2cm" margin-bottom="2cm" 
                margin-left="2cm" margin-right="1cm">
                <fo:region-body 
                    region-name="xsl-region-body"/>
            </fo:simple-page-master>
        </fo:layout-master-set>

        <fo:page-sequence master-reference="page-recto">
            <fo:flow flow-name="xsl-region-body" 
                font-family="Times" font-weight="normal" 
                font-size="8pt" space-before="8pt" space-after="8pt"
                text-align="justify" end-indent="120pt">
                <xsl:apply-templates/>
            </fo:flow>
        </fo:page-sequence>

    </fo:root>
</xsl:template>

<xsl:template match="text">
    <fo:block 
        page-break-inside="avoid"
        font-size="9pt" font-weight="bold" 
        padding-bottom="1cm" end-indent="120pt">
        <xsl:apply-templates/>
    </fo:block>
</xsl:template>

<xsl:template match="seg[@type='dep_event']">
    <fo:block
        font-family="Times" font-weight="normal"
        font-size="8pt" space-before="8pt"
        space-after="8pt" text-align="justify"
        end-indent="2.5in">
        <xsl:if test=".//add[@type='margin_gloss']">
            <fo:float float="right">
                <fo:block-container width="2in" margin="10pt">
                    <fo:block font-size="7pt">
                            <xsl:apply-templates select=".//add[@type='margin_gloss']"/>
                    </fo:block>
                </fo:block-container>
            </fo:float>
        </xsl:if>
        <xsl:apply-templates/>
    </fo:block>
</xsl:template>

<xsl:template match="add[@type='margin_gloss']">
    <xsl:apply-templates/>
</xsl:template>

<xsl:template match="foreign">
    <fo:inline font-style="italic">
        <xsl:apply-templates/>
    </fo:inline>
</xsl:template>

<xsl:template match="supplied[@reason='added']">
    <xsl:text>[</xsl:text><xsl:apply-templates/><xsl:text>]</xsl:text>
</xsl:template>


</xsl:stylesheet>

Produces this problem output - the formatted contents of <add type="margin_gloss"> (I've highlighted in yellow) should only appear in the margin, not the body:

I've tried various forms of <apply-templates> but they either mangle/ignore the markup in the margin note (eg: <xsl:apply-templates select="descendant::add[@type='margin_gloss']/text()"/>), or disappear the margin note altogether.

I should note that I am using xsl:fo processor RenderX for full support of <fo:float>.

Thanks in advance.

回答1:

The problem is that your <add type="margin_gloss"> is being selected twice. First by this line...

<xsl:apply-templates select=".//add[@type='margin_gloss']"/>

And then by this line...

<xsl:apply-templates/>

One way to get around this, is to change the explicit xsl:apply-templates to this...

<xsl:for-each select=".//add[@type='margin_gloss']">
    <xsl:apply-templates />
</xsl:for-each>

Then, change the template matching add[@type='margin_gloss'] to this, as this will prevent it being processed a second time by the xsl:apply-templates

<xsl:template match="add[@type='margin_gloss']" />

So, the two relevant templates will look like this....

<xsl:template match="seg[@type='dep_event']">
    <fo:block
        font-family="Times" font-weight="normal"
        font-size="8pt" space-before="8pt"
        space-after="8pt" text-align="justify"
        end-indent="2.5in">
        <xsl:if test=".//add[@type='margin_gloss']">
            <fo:float float="right">
                <fo:block-container width="2in" margin="10pt">
                    <fo:block font-size="7pt">
                        <xsl:for-each select=".//add[@type='margin_gloss']">
                            <xsl:apply-templates />
                        </xsl:for-each>
                    </fo:block>
                </fo:block-container>
            </fo:float>
        </xsl:if>
        <xsl:apply-templates/>
    </fo:block>
</xsl:template>

<xsl:template match="add[@type='margin_gloss']"/>


标签: xml xslt xsl-fo