xsl tutorial transformar las hojas example estilo ejemplos ejemplo aplicaciĆ³n xslt xpath xslt-1.0

tutorial - xslt example



XSLT: ordena por el menor de 2 valores (3)

(respuesta actualizada para incluir pensamientos tanto en XSLT 1.0 como en 2.0)

I. XSLT 1.0:

Tenga en cuenta que XSLT 1.0 no tiene un equivalente incorporado a min() ; suponiendo que su analizador es compatible con EXSLT , puede hacer uso de su función math:min() para lograr una solución bastante similar a la variante XSLT 2.0 siguiente.

II. XSLT 2.0:

Aquí hay una solución que hace uso de la función de agregación XPath 2.0 min() .

Cuando esta solución XSLT 2.0:

<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> <xsl:output omit-xml-declaration="no" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <xsl:template match="products"> <products> <xsl:apply-templates select="product"> <xsl:sort select="min(price/offer|price/orig)" data-type="number" order="ascending" /> </xsl:apply-templates> </products> </xsl:template> </xsl:stylesheet>

..se aplica al XML proporcionado:

<products> <product> <name>Product 1</name> <price> <orig>15</orig> <offer>10</offer> </price> </product> <product> <name>Product 2</name> <price> <orig>13</orig> <offer>12</offer> </price> </product> <product> <name>Product 3</name> <price> <orig>11</orig> </price> </product> </products>

..el resultado deseado se produce:

<?xml version="1.0" encoding="UTF-8"?> <products> <product> <name>Product 1</name> <price> <orig>15</orig> <offer>10</offer> </price> </product> <product> <name>Product 3</name> <price> <orig>11</orig> </price> </product> <product> <name>Product 2</name> <price> <orig>13</orig> <offer>12</offer> </price> </product> </products>

Tengo un XML que está formateado de la siguiente manera:

<products> <product> <name>Product 1</name> <price> <orig>15</orig> <offer>10</offer> </price> </product> <product> <name>Product 2</name> <price> <orig>13</orig> <offer>12</offer> </price> </product> <product> <name>Product 3</name> <price> <orig>11</orig> </price> </product> </products>

Necesito ordenar los productos usando XSLT 1.0 (en orden ascendente o descendente) según su precio actual. Mi dificultad radica en el hecho de que tengo que ordenar el menor de los dos posibles valores de precio <orig> y <offer> si ambos existen.

Para el ejemplo anterior, el orden correcto sería:

  • Producto 1 (valor más bajo = 10)
  • Producto 3 (valor más bajo = 11)
  • Producto 2 (valor más bajo = 12)

Cualquier ayuda sería muy apreciada, ya que parece que no puedo encontrar una pregunta similar a través de la búsqueda.


I. Existe una solución XSLT 1.0 general y pura, tan simple como esto :

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <xsl:template match="/*"> <products> <xsl:apply-templates select="*"> <xsl:sort data-type="number" select= "price/*[not(../* &lt; .)]"/> </xsl:apply-templates> </products> </xsl:template> </xsl:stylesheet>

II. Si el price tiene otros hijos además de offer y orig - en este caso la solución general I. arriba (al igual que las otras dos respuestas a esta pregunta) no funciona correctamente.

Aquí hay una solución correcta para este caso :

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <xsl:template match="/*"> <products> <xsl:apply-templates select="*"> <xsl:sort data-type="number" select= "sum(price/orig[not(../offer &lt;= .)]) + sum(price/offer[not(../orig &lt; .)]) "/> </xsl:apply-templates> </products> </xsl:template> </xsl:stylesheet>

III. Si sabemos que la offer nunca excede orig :

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <xsl:template match="/*"> <products> <xsl:apply-templates select="*"> <xsl:sort data-type="number" select="price/offer | price/orig[not(../offer)]"/> </xsl:apply-templates> </products> </xsl:template> </xsl:stylesheet>

IV. Verificación :

Las tres transformaciones anteriores, cuando se aplican al documento XML proporcionado:

<products> <product> <name>Product 1</name> <price> <orig>15</orig> <offer>10</offer> </price> </product> <product> <name>Product 2</name> <price> <orig>13</orig> <offer>12</offer> </price> </product> <product> <name>Product 3</name> <price> <orig>11</orig> </price> </product> </products>

producir el resultado deseado y correcto :

<products> <product> <name>Product 1</name> <price> <orig>15</orig> <offer>10</offer> </price> </product> <product> <name>Product 3</name> <price> <orig>11</orig> </price> </product> <product> <name>Product 2</name> <price> <orig>13</orig> <offer>12</offer> </price> </product> </products>

La Solución II es la única de las tres que todavía produce el resultado correcto cuando se aplica en este documento XML (se agregó un price minAcceptable para el niño):

<products> <product> <name>Product 1</name> <price> <orig>15</orig> <offer>10</offer> <minAcceptable>8</minAcceptable> </price> </product> <product> <name>Product 2</name> <price> <orig>13</orig> <offer>12</offer> <minAcceptable>6</minAcceptable> </price> </product> <product> <name>Product 3</name> <price> <orig>11</orig> <minAcceptable>7</minAcceptable> </price> </product> </products>

Tenga en cuenta que ninguna de las otras respuestas procesa este documento XML correctamente.


Una solución XSLT 1.0 que no requiere EXSLT:

<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output omit-xml-declaration="no" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <xsl:template match="products"> <products> <xsl:apply-templates select="product"> <xsl:sort select="(price/*[not(. > ../*)])[1]" data-type="number" order="ascending" /> </xsl:apply-templates> </products> </xsl:template> </xsl:stylesheet>