Ejemplo sencillo de "extracción" xsl:for-each

Este ejemplo utiliza <xsl:for-each> para "extraer" información seleccionada de los resultados OXML y crear tablas HTML personalizadas.

Aunque puede generar con facilidad los resultados HTML utilizando DESTINATION FORMAT=HTML en el comando OMS, tendría poco control sobre el HTML generado aparte de los tipos de objetos específicos incluidos en el archivo HTML. Mediante OXML, sin embargo, puede crear tablas personalizadas. Este ejemplo

  • selecciona únicamente las tablas de frecuencias del archivo OXML;
  • muestra únicamente los valores válidos (no perdidos);
  • muestra únicamente las columnas Frecuencia y Porcentaje válido;
  • sustituye las etiquetas de columna predeterminadas por Recuento y Porcentaje.

La hoja de estilo XSLT que se utiliza en este ejemplo es oms_simple_frequency_tables.xsl.

Nota: Esta hoja de estilo no está diseñada para trabajar con tablas de frecuencia generadas con procesamiento de archivos segmentados por capas.

Figura 1. Hoja de estilo XSLT: oms_simple_frequency_tables.xsl
<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="1.0" xmlns:oms="http://xml.spss.com/spss/oms">
<!--enclose everything in a template, starting at the root node-->
<xsl:template match="/">
<HTML>
<HEAD>
<TITLE>Modified Frequency Tables</TITLE>
</HEAD>
<BODY>
<!--Find all Frequency Tables-->
<xsl:for-each select="//oms:pivotTable[@subType='Frequencies']">
<xsl:for-each select="oms:dimension[@axis='row']">
 <h3>
  <xsl:value-of select="@text"/>
 </h3>
</xsl:for-each>
<!--create the HTML table-->
<table border="1">
 <tbody align="char" char="." charoff="1">
 <tr>
  <!--
  table header row; you could extract headings from 
  the XML but in this example we're using different header text
  -->
  <th>Category</th><th>Count</th><th>Percent</th>
 </tr>
 <!--find the columns of the pivot table-->
 <xsl:for-each select="descendant::oms:dimension[@axis='column']">
   <!--select only valid, skip missing-->
    <xsl:if test="ancestor::oms:group[@text='Valid']">
     <tr>
     <td>
       <xsl:choose>
        <xsl:when test="not((parent::*)[@text='Total'])">
         <xsl:value-of select="parent::*/@text"/>
        </xsl:when>
        <xsl:when test="((parent::*)[@text='Total'])">
         <b><xsl:value-of select="parent::*/@text"/></b>
        </xsl:when>
       </xsl:choose>
     </td>
     <td>
      <xsl:value-of select="oms:category[@text='Frequency']/oms:cell/@text"/>      
     </td>
     <td>
      <xsl:value-of select="oms:category[@text='Valid Percent']/oms:cell/@text"/>
     </td>
    </tr>
  </xsl:if>
  </xsl:for-each>
 </tbody>
</table>
<!--Don't forget possible footnotes for split files-->
<xsl:if test="descendant::*/oms:note">
<p><xsl:value-of select="descendant::*/oms:note/@text"/></p>
</xsl:if>
</xsl:for-each>
</BODY>
</HTML>
</xsl:template>
</xsl:stylesheet>
  • xmlns:oms="http://xml.spss.com/spss/oms" define "oms" como el prefijo que identifica al espacio de nombres; por tanto, todos los nombres de los elementos de las expresiones de XPath deben incluir el prefijo "oms:".
  • El XSLT se compone principalmente de una serie de sentencias <xsl:for-each> anidadas, cada una de las cuales profundiza hasta un elemento y atributo diferentes de la tabla.
  • <xsl:for-each select="//oms:pivotTable[@subType='Frequencies']"> selecciona todas las tablas del subtipo 'Frecuencias'.
  • <xsl:for-each select="oms:dimension[@axis='row']"> selecciona la dimensión de las filas de cada tabla.
  • <xsl:for-each select="descendant::oms:dimension[@axis='column']"> selecciona los elementos de columna de dicha fila. OXML representa las tablas por fila, por lo que los elementos de columna se anidan dentro de los elementos de fila.
  • <xsl:if test="ancestor::oms:group[@text='Valid']"> selecciona únicamente la sección de la tabla que contiene valores no perdidos válidos. Si hay ningún valor perdido indicado en la tabla, esto incluiría toda la tabla. Esta especificación es la primera de las diferentes especificaciones XSLT de este ejemplo que dependen de valores de los atributos que son diferentes según el idioma de los resultados. Si no necesita una solución que trabaje con resultados en varios idiomas, ésta es frecuentemente la manera más sencilla y más directa de seleccionar determinados elementos. Muchas veces, no obstante, hay alternativas que no dependen de las cadenas de texto localizadas. Consulte el tema Advanced xsl:for-each "Pull" Example para obtener más información.
  • <xsl:when test="not((parent::*)[@text='Total'])"> selecciona los elementos de columna que no se encuentran en la fila 'Total'. Una vez más, esta selección depende del texto localizado y el único motivo por el que diferenciamos en este ejemplo entre las filas que son totales y las que no lo son es para poner la etiqueta de fila 'Total' en negrita.
  • <xsl:value-of select="oms:category[@text='Frequency']/oms:cell/@text"/> obtiene el contenido de la casilla en la columna 'Frecuencia' de cada fila.
  • <xsl:value-of select="oms:category[@text='Valid Percent']/oms:cell/@text"/> obtiene el contenido de la celda en la columna 'Porcentaje válido' de cada fila. Tanto este código como el anterior para obtener el valor de la columna 'Frecuencia' dependen de texto localizado.