Home > Software engineering >  XSLT 3.0: Divide into groups when there is a direct appeal to the element
XSLT 3.0: Divide into groups when there is a direct appeal to the element

Time:06-20

I want to divide the xml into pages, where whenever there is an <eop> tag a new page starts. I have calls specific elements, and I see that it destroys the division .. When I put in the group: <xsl:apply-templates select="current-group()"/> That was fine. And because I changed to a specific call: <xsl:apply-templates select="current-group()/self::title"/> <xsl:apply-templates select="current-group()/self::article" it was destroyed ..

Anyone have an idea how to make specific calls in group ?

the xml code:

<?xml version="1.0" encoding="UTF-8"?>
<dataRoot >
    <eop eId="100"></eop>
    <article>
        <content>
            <p>page 100 article 1 p 1</p>
        </content>
        <title>article 1</title>
        <content>
            <point>
                <p>page 100 article 1 p 2</p>
                <p>page 100 article 1 p 3
                    <p>page 100 article 1 p 4
                        <eop eId="101"></eop>
                        page 101 article 1 p 5
                    </p>
                    <p>page 101 article 1 p 6</p>
                </p>
                <p>page 101 article 1 p 7

                </p>
            </point>
            <point>
                <p>page 101 article 1 p 8</p>
            </point>
        </content>
    </article>
    <article>
        <title>article 2</title>
        <content>
            <point>
                <p>page 101 article 2 p 1</p>
                <p>page 101 article 2 p 2

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

the 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" xmlns:text="my-namespace-uri" exclude-result-prefixes="xs" version="3.0" >
    <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>
    <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: 1em 2em;
                    background-color: #ffff;
                    }
                   
                   .eop{padding:2em;}
                    .numPage{padding:1rem 1rem 1rem 2rem;}
                </style>
            </head>
            <body>
                <xsl:apply-templates />
            </body>
        </html>
    </xsl:template>
    <xsl:template match="dataRoot">
        <xsl:for-each-group select=".//node()" group-starting-with="eop">
            <div >
                <div >
                    <xsl:apply-templates select="current-group()/self::title"/>
                    <xsl:apply-templates select="current-group()/self::article"/>
                </div>
            </div>
        </xsl:for-each-group>
    </xsl:template>
    <xsl:template match="eop">
        <div >
              number page:
            <xsl:value-of select="descendant-or-self::node()/@eId"/>
        </div>
    </xsl:template>
    <xsl:template match="article" >
        <div >
            <xsl:apply-templates />
        </div>
    </xsl:template>
    <xsl:template match="title">
        <xsl:value-of select="descendant-or-self::node()/text()"/>
    </xsl:template>
    <xsl:template match="content" >
        <div >
            <xsl:apply-templates />
        </div>
    </xsl:template>
    <xsl:template match="point">
        <xsl:apply-templates />
    </xsl:template>
    <xsl:template match="p" >
        <div >
            <xsl:value-of select="descendant-or-self::node()/text()"/>
        </div>
    </xsl:template>
</xsl:stylesheet>

the result: enter image description here

The page should end in eop 101 And instead ends at the end of Article 1

CodePudding user response:

Perhaps use two different modes, where you process all elements but the title in one mode that outputs the hierarchy of the current-group but blocks the title and the other outputs e.g. the title:

  <xsl:template match="dataRoot">
      <xsl:variable name="parent" select="."/>
      <xsl:for-each-group select="descendant::node()" group-starting-with="eop">
          <div >
            <div >
               <xsl:apply-templates select="current-group()[self::title]"/>
               <xsl:apply-templates select="$parent/node()[descendant-or-self::node() intersect current-group()]" mode="subtree"/>
            </div>
          </div>
      </xsl:for-each-group>
  </xsl:template>
  
  <xsl:template match="eop" mode="subtree"/>

  <xsl:template match="node()" mode="subtree">
      <xsl:copy>
          <xsl:copy-of select="@*"/>
          <xsl:apply-templates select="node()[descendant-or-self::node() intersect current-group()]" mode="subtree"/>
      </xsl:copy>
  </xsl:template>
  
  <xsl:template match="article/title" mode="subtree"/>
  
  <xsl:template match="article/title">
    <h2>
      <xsl:apply-templates/>
    </h2>
  </xsl:template>

Probably mapping the article/title to an h2 element is not what you want but of course you can let that template matching article/title create any output you want, so let that particular example above not confuse you, I just needed some way to distinguish the "special" processing of the title in the output from the processing of the rest of the group.

As for your comments, your own templates would be adapted e.g.

<xsl:template match="content" >
    <div >
        <xsl:apply-templates />
    </div>
</xsl:template>

would become

<xsl:template match="content" mode="subtree">
    <div >
      <xsl:apply-templates select="node()[descendant-or-self::node() intersect current-group()]" mode="subtree"/>
    </div>
</xsl:template>
  • Related