Search code examples
xmlpdfxsltsvgapache-fop

SVG elements in XML for pdf generation


I have the following xsl:

<fo:block space-before="5mm" font-size="12pt" display-align="center" text-align="center">

                <fo:instream-foreign-object background-color="white" content-height="200mm" content-width="150mm" height="200mm" width="150mm" padding="5pt">
                        <svg width="15cm" height="20cm" version="1.1" viewBox="0 0 300 300" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg">


                            <xsl:variable name="var_span">
                                <xsl:value-of select="pdftest/span" />
                            </xsl:variable>
                            <xsl:variable name="var_width2Balken">
                                <xsl:value-of select="pdftest/width2Balken" />
                            </xsl:variable>
                            <xsl:variable name="var_xoffset">
                                <xsl:value-of select="pdftest/xoffset" />
                            </xsl:variable>
                            <xsl:variable name="var_yoffset">
                                <xsl:value-of select="pdftest/yoffset" />
                            </xsl:variable>
                            <xsl:variable name="var_yMax">
                                <xsl:value-of select="pdftest/yMax" />
                            </xsl:variable>
                            <xsl:variable name="var_yMin">
                                <xsl:value-of select="pdftest/yMin" />
                            </xsl:variable>
                            <xsl:variable name="var_xMax">
                                <xsl:value-of select="pdftest/xMax" />
                            </xsl:variable>

                            <!-- <xsl:variable name="var_xLast"> <xsl:value-of select="0" /> </xsl:variable> -->




                            <!-- <line x1="{$var_xoffset}" y1="{$var_yoffset -100}" x2="{$var_xMax}" y2="{$var_yoffset -100}" style="stroke:gray;stroke-width:1;" /> -->


                            <line x1="{$var_xoffset}" y1="{$var_yoffset}" x2="{$var_xMax + $var_xoffset}" y2="{$var_yoffset}" style="stroke:black;stroke-width:5;" />
                            <line x1="{$var_xoffset}" y1="0" x2="{$var_xoffset}" y2="{$var_yMin + $var_yMax}" style="stroke:black;stroke-width:5;" />





                        </svg>
                    </fo:instream-foreign-object>

                    </fo:block>

and the following XML:

<pdftest>
    <span>10</span>
    <width2Balken>38</width2Balken>
    <xoffset>0</xoffset>
    <yoffset>280</yoffset>
    <xMax>300</xMax>
    <yMax>200</yMax>
    <yMin>100</yMin>
</pdftest>

I know it works fine when using fop1.1 to generate pdf.

My question however is: Is it possible to but everything in the xml (the part of the xsl AND the xml part) and then only have 1 tag to show it in the xsl without all the logic and so on?

So in the end you would have

XSL: <xsl:value-of select="svg-all"> 

and in the XML your have

<svg-all>all of the above xsl with the xml values</svg-all>

I know it is not the best of programming and having all controll element in the xsl is better, but I was wondering if it is possible and how. Any help would be great.

Thanks. TheVagabond


Solution

  • You simply need to use xsl:copy-of, rather than xsl:value-of.

    Suppose you had XML like so...

    <pdftest>
        <span>10</span>
        <width2Balken>38</width2Balken>
        <xoffset>0</xoffset>
        <yoffset>280</yoffset>
        <xMax>300</xMax>
        <yMax>200</yMax>
        <yMin>100</yMin>
        <svg-all xmlns="http://www.w3.org/2000/svg">
            <line x1="0" y1="280" x2="300" y2="280" style="stroke:black;stroke-width:5;" />
            <line x1="0" y1="0" x2="0" y2="300" style="stroke:black;stroke-width:5;" />
        </svg-all>    
    </pdftest>
    

    Then the creation of the fo:block would look like this...

    <fo:block space-before="5mm" font-size="12pt" display-align="center" text-align="center">
        <fo:instream-foreign-object background-color="white" content-height="200mm" content-width="150mm" height="200mm" width="150mm" padding="5pt">
            <svg width="15cm" height="20cm" version="1.1" viewBox="0 0 300 300" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg">
                <xsl:copy-of select="pdftest/svg:svg-all/*" />
            </svg>
        </fo:instream-foreign-object>
    </fo:block>
    

    Note that you would need to declare the svg namespace in your XSLT

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
         xmlns:svg="http://www.w3.org/2000/svg">
    

    As an aside, you can simplify your current XSLT. For example, the xsl:variable declarations can be simplified. Instead of writing this...

    <xsl:variable name="var_span">
        <xsl:value-of select="pdftest/span" />
    </xsl:variable>
    

    You can write just this...

    <xsl:variable name="var_span" select="pdftest/span" />
    

    You could further simplify your current XSLT by having a template matching pdftest, and even removing the variables altogether. For example, consider this...

    <xsl:template match="/">
        <fo:block space-before="5mm" font-size="12pt" display-align="center" text-align="center">
            <fo:instream-foreign-object background-color="white" content-height="200mm" content-width="150mm" height="200mm" width="150mm" padding="5pt">
                <xsl:apply-templates select="pdftest" mode="svg" />
            </fo:instream-foreign-object>
        </fo:block>
    </xsl:template>
    
    <xsl:template match="pdftest" mode="svg">
        <svg width="15cm" height="20cm" version="1.1" viewBox="0 0 300 300" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg">
            <line x1="{xoffset}" y1="{yoffset}" x2="{xMax + xoffset}" y2="{yoffset}" style="stroke:black;stroke-width:5;" />
            <line x1="{xoffset}" y1="0" x2="{xoffset}" y2="{yMin + yMax}" style="stroke:black;stroke-width:5;" />
        </svg>
    </xsl:template>