XSLT 3.0: Division into pages with direction

Issue

I have XML that describes a document, I try with XSLT to convert it to an HTML document that is divided into pages (each ‘eop’ tag indicates the beginning of a page). On each even number page the direction will be rtl and on the odd page the direction will be ltr.
Each page should be divided into two parts, with the title in one part and the content in the other
I tried but what happens is that from ‘article’ tag works fine but part of the ‘eop’ tag to the ‘article’ tag remains the previous settings.

Anyone have a solution?

xml:

<?xml version="1.0" encoding="UTF-8"?>
<dataRoot >
    <eop eId="100"></eop>
    <article>
        <title>article 1</title>
        <content>
            <point>
                <p>aaa</p>
                <p>bbb
                    <eop eId="101"></eop>
                </p>
                <p>ccc

                </p>
            </point>
            <point>
                <p>ddd</p>
                <p>eee</p>
            </point>
            <p>fff</p>
        </content>
    </article>
    <article>
        <title>article 2</title>
        <content>
            <point>
                <p>ggg</p>
                <p>hhh

                </p>
            </point>
        </content>
    </article>
</dataRoot>

xslt:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="3.0" >
    <xsl:mode use-accumulators="#all" streamable="no"/>
    <xsl:output omit-xml-declaration="no" indent="yes"/>
    <xsl:accumulator name="directionByPage" as="xs:string?" initial-value="'dir_rtl'">
        <xsl:accumulator-rule match="eop" select="if (number(translate(@eId, translate(@eId, '0123456789', ''), '')) mod 2 = 0) then 'dir_rtl' else 'dir_ltr'"/>
    </xsl:accumulator>
    <xsl:template match="/">
        <html>
            <head>
                <style type="text/css">
                    .dir_rtl{   text-align: right;   display: grid;    direction: rtl;    grid-template-columns: 20% 80%;                   }
                    .dir_ltr{    text-align: right;  display: grid;    direction: ltr;    grid-template-columns: 15% 85%;                   }
                    .page{
                    margin: 7em;
                    background-color: rgb(68,68,68); /* Needed for IEs */
                    
                    -moz-box-shadow: 5px 5px 5px rgba(68,68,68,0.6);
                    -webkit-box-shadow: 5px 5px 5px rgba(68,68,68,0.6);
                    box-shadow: 0px 1px 5px rgb(68 68 68 / 60%);
                    
                    filter: progid:DXImageTransform.Microsoft.Blur(PixelRadius=3,MakeShadow=true,ShadowOpacity=0.30);
                    -ms-filter: "progid:DXImageTransform.Microsoft.Blur(PixelRadius=3,MakeShadow=true,ShadowOpacity=0.30)";
                    zoom: 1;
                    }
                    .page .content {
                    position: relative; /* This protects the inner element from being blurred */
                    padding: 10em 5em;
                    background-color: #ffff;
                    }
                   
                   .eop{padding:4em;}
                    .numPage{padding:2rem 1rem 2rem 2rem;}
                </style>
            </head>
            <body>
                <xsl:apply-templates />
            </body>
        </html>
    </xsl:template>
    <xsl:template match="dataRoot" >
        <div class="page">
            <div class="content">
                <xsl:apply-templates />
            </div>
        </div>
    </xsl:template>
    <xsl:template match="eop">
        <div class="eop">
-----------------------------------------------------------------------
        </div>
        <div class="numPage">
              number page:
            <xsl:value-of select="@eId"/>
        </div>
    </xsl:template>
    <xsl:template match="article" >
        <div class="article">
            <div>
                <xsl:attribute name="class">
                    <xsl:value-of select="accumulator-before('directionByPage')"/>
                </xsl:attribute>
                <xsl:apply-templates />
            </div>
        </div>
    </xsl:template>
    <xsl:template match="title" >
        <div class="title">
            <xsl:value-of select="text()"/>
        </div>
    </xsl:template>
    <xsl:template match="content" >
        <div class="content">
            <xsl:apply-templates />
        </div>
    </xsl:template>
    <xsl:template match="point" >
        <div class="point">
            <xsl:apply-templates />
        </div>
    </xsl:template>
    <xsl:template match="p" >
        <div class="p">
            <xsl:apply-templates />
        </div>
    </xsl:template>
</xsl:stylesheet>

output html:

enter image description here

We see here that the direction does not change from the beginning of the page but only from the beginning of the article (because the name of the page is divided into grid)
The question is whether there is a possibility that each component will look for the ‘eop’ that precedes it (even when it is not at the same level in the xml tree)
Or someone has another solution

Solution

The text direction doesn’t apply at the article level, but at the level of individual elements within the article, so you will need to specify the appropriate direction class on all of those elements.

My advice is to add a function which will return the appropriate class name for each element, by finding the immediately-preceding eop and checking whether its number is odd or even, then you can call that function from each template to generate the appropriate class.

<xsl:function name="text:direction">
    <xsl:param name="element"/>
    <xsl:variable name="eId" select="$element/preceding-sibling::eop[1]/@eId"/>
    <xsl:sequence select="
        if (number(translate($eId, translate($eId, '0123456789', ''), '')) mod 2 = 0) then
            'dir_rtl' 
        else 
            'dir_ltr'
    "/>
</xsl:function>

Then in every one of your templates, call this function to add the appropriate directional class, e.g.

<xsl:template match="article" >
    <div class="article">
        <div class="{text:direction(.)}">
            <xsl:apply-templates />
        </div>
    </div>
</xsl:template>

<xsl:template match="title" >
    <div class="title {text:direction(.)}">
        <xsl:value-of select="text()"/>
    </div>
</xsl:template>

<!-- etc. -->

Note that the name of the function has a namespace prefix; this is mandatory for stylesheet functions. So you’ll need to include a declaration for that namespace e.g. xmlns:text="my-namespace-uri" on the stylesheet element.

Answered By – Conal Tuohy

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published