Search code examples
xmlxslt-2.0

MIN and MAX values and at what time it was


I am reffering to this question XSL transformation - XML data to HTML table. How to find out a min and max values of @label="memory" and @label="cpu" and what @time it was?

 <?xml version="1.0" encoding="UTF-8"?>
    <root>
        <sample time="14" label="cpu_0">
            <value>22</value>
        </sample>
        <sample time="14" label="cpu_2">
            <value>6</value>
        </sample>
        <sample time="1" label="cpu_2">
            <value>4</value>
        </sample>
        <sample time="14" label="memory">
            <value>97</value>
        </sample>
        <sample time="1" label="cpu_0">
            <value>28</value>
        </sample>
        <sample time="14" label="cpu_1">
            <value>52</value>
        </sample>
        <sample time="1" label="memory">
            <value>55</value>
        </sample>
        <sample time="1" label="cpu_1">
            <value>21</value>
        </sample>
    </root>

Wantend result

MEMORY
syntax: min/max: @value (@time)
min: 55 (1)
max: 97 (14)

CPU
syntax: min/max (CPU_number): @value (@time)
min: (CPU_2): 4 (1)
max: (CPU_1): 52 (14)

I am using XSLT 2.0


Solution

  • If you group by the label attribute or rather that attribute with the suffix _digit stripped for the CPU values and then sort each group by the value you can then output the first (min) and last (max) of the sorted group members:

    <?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"
        expand-text="yes"
        version="3.0">
    
      <xsl:output method="text"/>
    
      <xsl:template match="root">
          <xsl:for-each-group select="sample" group-by="replace(@label, '_[0-9]+$', '')">
              <xsl:value-of select="upper-case(current-grouping-key())"/>:
              <xsl:for-each select="current-group()">
                  <xsl:sort select="xs:decimal(value)"/>
                  <xsl:if test="position() eq 1">
                      min : {value} ({@time})
                  </xsl:if>
                  <xsl:if test="position() eq last()">
                      max : {value} ({@time})
                  </xsl:if>          </xsl:for-each>
          </xsl:for-each-group>
      </xsl:template>
    
    </xsl:stylesheet>
    

    The above and the online sample https://xsltfiddle.liberty-development.net/pPqsHT1/1 is using XSLT 3 but the grouping and sorting is the same in XSLT 2, you only would need to output any needed data with xsl:value-of instead of the text value templates using {}.