Pregunta

Tengo un archivo XML de muestra donde root tiene elemento con el nombre "elemento". Estos elementos pueden ser anidados.

Me gustaría excluir elementos con el nombre de "posición" donde "posición" valor x = ("número" + "otro") * El recuento es mayor que el promedio de suma (("número" + "otro") * "contar") de todos los elementos de "posición".

Cómo procesar este archivo XML con 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>
¿Fue útil?

Solución

Usaría el siguiente enfoque de dos pasos:

<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>

Cuando se aplica en el documento XML proporcionado:

<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>

Se produce el resultado correcto y correcto:

<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>

Otros consejos

Solo por diversión, esta hoja de estilo sin extensiones:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:variable name="vAvgPosition">
        <xsl:apply-templates select="/descendant::position[1]"
                             mode="avgPosition"/>
    </xsl:variable>
    <xsl:template match="node()|@*" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="position" mode="avgPosition">
        <xsl:param name="pSum" select="0"/>
        <xsl:param name="pCount" select="0"/>
        <xsl:variable name="vSum"
                      select="$pSum + (number + another) * count"/>
        <xsl:variable name="vCount" select="$pCount + 1"/>
        <xsl:variable name="vNext" select="following::position[1]"/>
        <xsl:apply-templates select="$vNext" mode="avgPosition">
            <xsl:with-param name="pSum" select="$vSum"/>
            <xsl:with-param name="pCount" select="$vCount"/>
        </xsl:apply-templates>
        <xsl:if test="not($vNext)">
            <xsl:value-of select="$vSum div $vCount"/>
        </xsl:if>
    </xsl:template>
    <xsl:template match="position">
        <xsl:if test="not((number + another) * count > $vAvgPosition)">
            <xsl:call-template name="identity"/>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

Producción:

<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>

Mira cuán compacta es una solución XSLT 2.0:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:variable name="vAvgPosition"
         select="avg(//position/((number+another)*count))"/>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="position[(number+another)*count > $vAvgPosition]"/>
</xsl:stylesheet>
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top