简体   繁体   中英

how to process number ranges in xslt2.0

My XML.

<a>
 <range nr="1" no-range="1 2 3 4" oc="4"/>
 <range nr="2" no-range="41 42 43 44" oc="4"/>
 <range nr="3" no-range="43 44 45 46" oc="4"/>
 <range nr="4" no-range="50 51 52 53" oc="4"/>
 <range nr="5" no-range="53 54" oc="2"/>
 <range nr="6" no-range="60 61" oc="2"/>
</a>

I was trying this but not sure how to compare two arrays and print the difference:

<?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="2.0">
<xsl:template match="a">
    <xsl:variable name="bRannge">
        <xsl:for-each select="range">
            <xsl:variable name="aRange" select="tokenize(concat(@no-range, ' '), ' ')"/>
            <xsl:value-of select="$aRange"/>
        </xsl:for-each>
    </xsl:variable>
    <xsl:variable name="cRange" select="tokenize(normalize-space($bRannge), ' ')"/>
    <xsl:variable name="aSeq">
        <xsl:for-each select="1 to xs:integer(number($cRange[last()]))">
            <xsl:value-of select="position()"/>
            <xsl:text> </xsl:text>
        </xsl:for-each>
    </xsl:variable>        
    <xsl:variable name="bSeq" select="tokenize(normalize-space($aSeq), ' ')"/>
    [<xsl:value-of select="$cRange"/>]
    [<xsl:value-of select="$bSeq"/>]
    <!-- How to compare two arrays     -->
</xsl:template>

How can I get following report using xslt 2.0:

  1. Number ranges not in use 5-40, 47-49, 55-59
  2. 'nr 3' is overlapping with 'nr 2' overlapping number = 43, 44
  3. 'nr 5' is overlapping with 'nr 4' overlapping number = 53

You can create each sequence you have with a single expression and then compare them as follows:

<xsl:template match="a">
    <xsl:variable name="seq1" as="xs:integer*" 
                  select="for $s in range/@no-range/tokenize(., '\s+') 
                          return xs:integer($s)"/>
    <xsl:variable name="seq2" as="xs:integer*" 
                  select="1 to $seq1[last()]"/>

    [<xsl:value-of select="$seq1"/>]
    [<xsl:value-of select="$seq2"/>]
    [<xsl:value-of select="$seq2[not(. = $seq1)]"/>]
</xsl:template>

That outputs the sequence of integers not in your no-range attribute values:

[5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 47 48 49 55 56 57 58 59]

As for finding consecutive ranges, one way would be to use grouping as follows:

<xsl:template match="a">
    <xsl:variable name="seq1" as="xs:integer*" 
                  select="for $s in range/@no-range/tokenize(., '\s+') 
                          return xs:integer($s)"/>
    <xsl:variable name="seq2" as="xs:integer*" 
                  select="1 to $seq1[last()]"/>

    [<xsl:value-of select="$seq1"/>]
    [<xsl:value-of select="$seq2"/>]

    <xsl:variable name="seq3" as="xs:integer*" 
                  select="$seq2[not(. = $seq1)]"/>

    [<xsl:value-of select="$seq3"/>]
    <xsl:for-each-group select="$seq3" group-adjacent=". - position()">
      [<xsl:value-of select="current-group()[1], current-group()[last()]" 
                     separator=" - "/>]    
    </xsl:for-each-group>

which then gives

  [5 - 40]    

  [47 - 49]    

  [55 - 59] 

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