XML with filtering of nested elements with calculation using XSLT v1.0 C #

advertisements

I have got a sample xml file where root has element with name "element". This elements can be nested.

I would like to exclude elements with name "position" where "position" value x = ("number" + "another") * count is greater than average of sum(("number" + "another") * "count") from all "position" elements.

How to process this xml file with xslt v 1.

<?xml version="1.0" encoding="utf-8" ?>
<root>
  <element>
    <position>
      <number>
        1
      </number>
      <another>
        2
      </another>
      <count>
        3
      </count>
    </position>
    <position>
      <number>
        3
      </number>
      <another>
        1
      </another>
      <count>
        5
      </count>
    </position>
    <element>
      <position>
        <number>
          3
        </number>
        <another>
          3
        </another>
        <count>
          5
        </count>
      </position>
      <position>
        <number>
          3
        </number>
        <another>
          6
        </another>
        <count>
          5
        </count>
      </position>
      <element>
        <position>
          <number>
            3
          </number>
          <another>
            3
          </another>
          <count>
            5
          </count>
        </position>
        <position>
          <number>
            3
          </number>
          <another>
            7
          </another>
          <count>
            5
          </count>
        </position>
        <element>
          <position>
            <number>
              33
            </number>
            <another>
              4
            </another>
            <count>
              5
            </count>
          </position>
          <position>
            <number>
              34
            </number>
            <another>
              3
            </another>
            <count>
              5
            </count>
          </position>
        </element>
      </element>
    </element>
  </element>
  <element>
    <position>
      <number>
        5
      </number>
      <another>
        1
      </another>
      <count>
        2
      </count>
    </position>
    <position>
      <number>
        3
      </number>
      <another>
        3
      </another>
      <count>
        9
      </count>
    </position>
    <element>
      <position>
        <number>
          5
        </number>
        <another>
          3
        </another>
        <count>
          2
        </count>
      </position>
      <position>
        <number>
          3
        </number>
        <another>
          3
        </another>
        <count>
          5
        </count>
      </position>
    </element>
  </element>
</root>


I would use the following two-pass approach:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
 <xsl:output omit-xml-declaration="yes"/>

 <xsl:variable name="vrtfPass1">
  <xsl:apply-templates select="/*" mode="getScore"/>
 </xsl:variable>

 <xsl:variable name="vPass1" select="ext:node-set($vrtfPass1)/*"/>

 <xsl:variable name="vAverage" select=
  "sum($vPass1//position/@score) div count($vPass1//position)"/>

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

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

 <xsl:template match="/">
  <xsl:apply-templates select="$vPass1"/>
 </xsl:template>

 <xsl:template match="position" mode="getScore">
  <position score="{(number + another)*count}">
    <xsl:apply-templates mode="getScore"/>
  </position>
 </xsl:template>

 <xsl:template match="position">
  <xsl:if test="not(@score > $vAverage)">
   <position>
    <xsl:apply-templates mode="getScore"/>
   </position>
  </xsl:if>
 </xsl:template>
</xsl:stylesheet>

when applied on the provided XML document:

<root>
    <element>
        <position>
            <number>1</number>
            <another>2</another>
            <count>3</count>
        </position>
        <position>
            <number>3</number>
            <another>1</another>
            <count>5</count>
        </position>
        <element>
            <position>
                <number>3</number>
                <another>3</another>
                <count>5</count>
            </position>
            <position>
                <number>3</number>
                <another>6</another>
                <count>5</count>
            </position>
            <element>
                <position>
                    <number>3</number>
                    <another>3</another>
                    <count>5</count>
                </position>
                <position>
                    <number>3</number>
                    <another>7</another>
                    <count>5</count>
                </position>
                <element>
                    <position>
                        <number>33</number>
                        <another>4</another>
                        <count>5</count>
                    </position>
                    <position>
                        <number>34</number>
                        <another>3</another>
                        <count>5</count>
                    </position>
                </element>
            </element>
        </element>
    </element>
    <element>
        <position>
            <number>5</number>
            <another>1</another>
            <count>2</count>
        </position>
        <position>
            <number>3</number>
            <another>3</another>
            <count>9</count>
        </position>
        <element>
            <position>
                <number>5</number>
                <another>3</another>
                <count>2</count>
            </position>
            <position>
                <number>3</number>
                <another>3</another>
                <count>5</count>
            </position>
        </element>
    </element>
</root>

the wanted, correct result is produced:

<root>
    <element>
        <position>
            <number>1</number>
            <another>2</another>
            <count>3</count>
        </position>
        <position>
            <number>3</number>
            <another>1</another>
            <count>5</count>
        </position>
        <element>
            <position>
                <number>3</number>
                <another>3</another>
                <count>5</count>
            </position>
            <position>
                <number>3</number>
                <another>6</another>
                <count>5</count>
            </position>
            <element>
                <position>
                    <number>3</number>
                    <another>3</another>
                    <count>5</count>
                </position>
                <position>
                    <number>3</number>
                    <another>7</another>
                    <count>5</count>
                </position>
                <element>

                </element>
            </element>
        </element>
    </element>
    <element>
        <position>
            <number>5</number>
            <another>1</another>
            <count>2</count>
        </position>
        <position>
            <number>3</number>
            <another>3</another>
            <count>9</count>
        </position>
        <element>
            <position>
                <number>5</number>
                <another>3</another>
                <count>2</count>
            </position>
            <position>
                <number>3</number>
                <another>3</another>
                <count>5</count>
            </position>
        </element>
    </element>
</root>