简体   繁体   中英

global sequence numbering across different for each groups in XSLT 2.0

I have to generate an xml file where certain grouped elements (documents which group lines) are numbered with a sequence. In turn, these groups belong within another group (by document type). The numbering must be sequential during all the document, regardless of the group.

See the attribute DocId in the Documents element in the example output:

INPUT

<Entries>
    <Entry>
        <UserID>1</UserID>
        <DocNumber>1002</DocNumber>
        <Description>An invoice</Description>
        <Amount>3103.2000</Amount>
        <DocType>INVOICE</DocType>
    </Entry>
    <Entry>
        <UserID>2</UserID>
        <DocNumber>3001</DocNumber>
        <Description>Some receipt</Description>
        <Amount>2352.0000</Amount>
        <DocType>RECEIPT</DocType>
    </Entry>
    <Entry>
        <UserID>1</UserID>
        <DocNumber>1002</DocNumber>
        <Description>An invoice</Description>
        <Amount>2861.8400</Amount>
        <DocType>INVOICE</DocType>
    </Entry>
    <Entry>
        <UserID>2</UserID>
        <DocNumber>3001</DocNumber>
        <Description>Some receipt</Description>
        <Amount>2352.0000</Amount>
        <DocType>RECEIPT</DocType>
    </Entry>
    <Entry>
        <UserID>5</UserID>
        <DocNumber>1004</DocNumber>
        <Description>Another invoice</Description>
        <Amount>2.34</Amount>
        <DocType>INVOICE</DocType>
    </Entry>
</Entries>

XSLT 2.0

<xsl:stylesheet exclude-result-prefixes="xs xdt err fn" version="2.0" xmlns:err="http://www.w3.org/2005/xqt-errors" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xdt="http://www.w3.org/2005/xpath-datatypes" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ser="http://webservice">
    <xsl:output indent="yes" method="xml"/>
    <xsl:template match="/Entries">
        <ser:Request>
                <xsl:for-each-group select="Entry" group-by="DocType">
                    <xsl:sort select="current-grouping-key()"/>                    
                    <ser:ItemFile ImportName="{DocType}" Date="{current-date()}">
                        <xsl:for-each-group select="current-group()" group-by="DocNumber">
                            <xsl:sort select="current-grouping-key()"/>                            
                            <ser:Documents DocId="{position()}" DocRef="{DocNumber}" Desc="{Description}" >
                                <xsl:for-each select="current-group()">
                                    <Line amount="{Amount}"/>
                                </xsl:for-each>
                            </ser:Documents>
                        </xsl:for-each-group>
                    </ser:ItemFile>
                </xsl:for-each-group>
        </ser:Request>
    </xsl:template>
</xsl:stylesheet>

OUTPUT

<ser:Request xmlns:ser="http://webservice">
   <ser:ItemFile ImportName="INVOICE" Date="2017-10-13+02:00">
      <ser:Documents DocId="1" DocRef="1002" Desc="An invoice">
         <Line amount="3103.2000"/>
         <Line amount="2861.8400"/>
      </ser:Documents>
      <ser:Documents DocId="2" DocRef="1004" Desc="Another invoice">
         <Line amount="2.34"/>
      </ser:Documents>
   </ser:ItemFile>
   <ser:ItemFile ImportName="RECEIPT" Date="2017-10-13+02:00">
      <ser:Documents DocId="1" DocRef="3001" Desc="Some receipt">
         <Line amount="2352.0000"/>
         <Line amount="2352.0000"/>
      </ser:Documents>
   </ser:ItemFile>
</ser:Request>

In this example, the desired output for last DocId attribute would be 3, following the sequence.

I noticed if I use the position() function, the numbering restarts in each group, which is not what I want. I also tried the xsl:number element with no success. I considered counting the elements in the first group and adding it to position(), which worked for me for a limited number of groups, but couldn't do it generically for a variable number of groups.

Is there some relatively simple way of achieving this? Thank you in advance.

I would store the newly created elements in a variable and then push it through templates that copy everything but that DocId attribute where you can then use xsl:number to set it:

<xsl:stylesheet exclude-result-prefixes="xs xdt err fn" version="2.0" xmlns:err="http://www.w3.org/2005/xqt-errors" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xdt="http://www.w3.org/2005/xpath-datatypes" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ser="http://webservice">
    <xsl:output indent="yes" method="xml"/> 

    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>  
    </xsl:template>

    <xsl:template match="/Entries">
        <ser:Request>
            <xsl:variable name="result">
                 <xsl:for-each-group select="Entry" group-by="DocType">
                    <xsl:sort select="current-grouping-key()"/>                    
                    <ser:ItemFile ImportName="{DocType}" Date="{current-date()}">
                        <xsl:for-each-group select="current-group()" group-by="DocNumber">
                            <xsl:sort select="current-grouping-key()"/>                            
                            <ser:Documents DocId="" DocRef="{DocNumber}" Desc="{Description}" >
                                <xsl:for-each select="current-group()">
                                    <Line amount="{Amount}"/>
                                </xsl:for-each>
                            </ser:Documents>
                        </xsl:for-each-group>
                    </ser:ItemFile>
                </xsl:for-each-group>           
            </xsl:variable>
            <xsl:apply-templates select="$result"/>
        </ser:Request>
    </xsl:template>

    <xsl:template match="ser:Documents/@DocId">
        <xsl:attribute name="{name()}">
            <xsl:number select=".." level="any"/>
        </xsl:attribute>
    </xsl:template>
</xsl:stylesheet>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM