2011-09-15 19 views
10

cómo dividir un valor de nodo en XSLT 1.0?función de división en xslt 1.0

<mark>1,2</mark> 

necesito realizar algunas operaciones en el ciclo for con cada valor de la salida de split.

<xsl:for-each select=""> </xsl:for-each>

Cómo hacer esto?

+0

¿Hay siempre dos elementos en el valor, o es un número variable? –

+0

puede variar.Es el valor de la marca de nodo. –

+0

Buena pregunta, +1. Dependiendo de qué versión de XSLT (1.0 o 2.0) se use, esto se puede hacer, con procesamiento recursivo o simplemente usando la función estándar de XPath 2.0 'tokenize()'. –

Respuesta

12

I. XSLT 1.0 solución:

Aquí es una manera de hacer esto en XSLT 1.0 usando sólo la función xxx:node-set() extensión:

<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" indent="yes"/> 

<xsl:template match="mark"> 
    <xsl:variable name="vrtfSplit"> 
    <xsl:apply-templates/> 
    </xsl:variable> 

    <xsl:for-each select="ext:node-set($vrtfSplit)/*"> 
    <processedItem> 
    <xsl:value-of select="10 * ."/> 
    </processedItem> 
    </xsl:for-each> 
</xsl:template> 

<xsl:template match="text()" name="split"> 
    <xsl:param name="pText" select="."/> 
    <xsl:if test="string-length($pText) >0"> 
    <item> 
    <xsl:value-of select= 
     "substring-before(concat($pText, ','), ',')"/> 
    </item> 

    <xsl:call-template name="split"> 
    <xsl:with-param name="pText" select= 
    "substring-after($pText, ',')"/> 
    </xsl:call-template> 
    </xsl:if> 
</xsl:template> 
</xsl:stylesheet> 

cuando esta transforma ación se aplica al siguiente documento XML:

<mark>1,2,3,4,5</mark> 

La quería, salida correcta (cada elemento multiplicado por 10) se produce:

II. solución de XSLT 2.0:

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    exclude-result-prefixes="xs"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:template match="mark"> 
    <xsl:for-each select="tokenize(., ',')"> 
    <processedItem> 
    <xsl:sequence select="10*xs:integer(.)"/> 
    </processedItem> 
    </xsl:for-each> 
</xsl:template> 
</xsl:stylesheet> 
1

En 1.0 se necesita para escribir una plantilla recursiva - excepto no lo hace, porque ya ha sido escrito. Descargue la plantilla str:tokenize de http://www.exslt.org.

4

La explicación por Dimitre Novatchev es impresionante, pero también puede hacerlo en forma mucho más sencilla sin necesidad de utilizar node-set() función tenga una mirada:

<?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="yes" indent="yes"/> 



    <xsl:variable name="delimiter"> 
     <xsl:text>,</xsl:text> 
    </xsl:variable> 



    <xsl:template match="mark"> 
     <xsl:variable name="dataList"> 
      <xsl:value-of select="."/> 
     </xsl:variable> 
     <xsl:call-template name="processingTemplate"> 
      <xsl:with-param name="datalist" select="$dataList"/> 
     </xsl:call-template> 
    </xsl:template> 

    <xsl:template name="processingTemplate"> 
     <xsl:param name="datalist"/> 


     <xsl:choose> 
     <xsl:when test="contains($datalist,$delimiter) "> 
       <xsl:element name="processedItem"> 
        <xsl:value-of select="substring-before($datalist,$delimiter) * 10"/> 
       </xsl:element> 
       <xsl:call-template name="processingTemplate"> 
        <xsl:with-param name="datalist" select="substring-after($datalist,$delimiter)"/> 
       </xsl:call-template> 
     </xsl:when> 
      <xsl:when test="string-length($datalist)=1"> 
       <xsl:element name="processedItem"> 
        <xsl:value-of select="$datalist * 10"/> 

        </xsl:element> 
      </xsl:when> 
     </xsl:choose>  

    </xsl:template> 
</xsl:stylesheet> 
0

Este código va a dividir una cadena delimitada en XSLT 1.0 (Funcionará para 2.0, pero no usará el conjunto de nodos.) También suprimirá opcionalmente elementos vacíos en la cadena u opcionalmente en mayúscula los elementos.

<!-- Example delimited string. --> 
<xsl:variable name="delimitedString" select="'a, b, c, , , d, e, f, g'"/> 

<!-- Create a node set where each node contains one of the elements from the 
    delimited string. --> 
<xsl:variable name="splitNodes"> 
    <xsl:call-template name="getNodeListFromDelimitedList"> 
    <xsl:with-param name="inStrList" select="$delimitedString"/> 
    <xsl:with-param name="delimiter" select="','"/> 
    <xsl:with-param name="suppressEmptyElements" select="false()"/> 
    <xsl:with-param name="upperCase" select="false()"/> 
    <xsl:with-param name="allTrim" select="false()"/> 
    </xsl:call-template>  
</xsl:variable> 

<!-- Use this for XSLT 1.0 only. --> 
<xsl:variable name="splitNodesList" select="msxml:node-set($splitNodes)"/> 

<!-- Use the split node list to do something. For example, create a string like 
    the delimited string, but without the delimiters. --> 
<xsl:variable name="nonDelimitedString"> 
    <xsl:for-each select="$splitNodesList/element"> 
    <xsl:value-of select="."/> 
    </xsl:for-each> 
</xsl:variable> 


<!-- Do something with the nonDelimitedString. --> 

<!-- 
***************************************************************************************** 

This template converts a delimited string list to a node list as follows: 

Each value in the delimited input string is extracted from the string. Then, a node is 
created to contain the value. The name of the node is 'element', and it is added to the 
list. To use this template, create an variable and call this template from within the variable. 
If you are using XSLT version 1.0, convert the node list to a node set using the node-set 
function. You can access the element as follows: $SomeVariableNodeSet/element 

***************************************************************************************** 
--> 
<xsl:template name="getNodeListFromDelimitedList"> 
    <!-- Delimited string with one or more delimiters. --> 
    <xsl:param name="inStrList"/> 
    <!-- The delimiter. --> 
    <xsl:param name="delimiter" select="'|'"/> 
    <!-- Set to true to suppress empty elements from being added to node list. Otherwise, set to 'false'.--> 
    <xsl:param name="suppressEmptyElements" select="true()"/> 
    <!-- Set to true to upper case the strings added to the node list. --> 
    <xsl:param name="upperCase" select="false()"/> 
    <!-- Set to true to left trim and right trim the strings added to the nodes list. --> 
    <xsl:param name="allTrim" select="false()"/> 

    <xsl:variable name="element"> 
    <xsl:choose> 
     <xsl:when test="contains($inStrList,$delimiter)"> 
     <xsl:value-of select="substring-before($inStrList,$delimiter)"/> 
     </xsl:when> 
     <xsl:otherwise> 
     <xsl:value-of select="$inStrList"/> 
     </xsl:otherwise> 
    </xsl:choose> 
    </xsl:variable> 

    <!-- Write out the element based on parameters. --> 
    <xsl:if test="not($suppressEmptyElements) or normalize-space($element) != ''"> 
    <!-- Put the element in the list. --> 
    <xsl:element name="element"> 
     <xsl:choose> 
     <xsl:when test="$allTrim"> 
      <xsl:call-template name="all-trim"> 
      <xsl:with-param name="inStr" select="$element"/> 
      <xsl:with-param name="upperCase" select="$upperCase"/> 
      </xsl:call-template> 
     </xsl:when> 
     <xsl:when test="$upperCase"> 
      <xsl:value-of select="translate($element, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:value-of select="$element"/> 
     </xsl:otherwise> 
     </xsl:choose> 
    </xsl:element> 
    </xsl:if> 

    <xsl:if test="contains($inStrList,$delimiter)"> 
    <!-- Call template recursively to process the next element. --> 
    <xsl:call-template name="getNodeListFromDelimitedList"> 
     <xsl:with-param name="inStrList" select="substring-after($inStrList,$delimiter)"/> 
     <xsl:with-param name="delimiter" select="$delimiter"/> 
     <xsl:with-param name="suppressEmptyElements" select="$suppressEmptyElements"/> 
     <xsl:with-param name="upperCase" select="$upperCase"/> 
     <xsl:with-param name="allTrim" select="$allTrim"/> 
    </xsl:call-template> 
    </xsl:if> 

</xsl:template> 


<!-- 
***************************************************************************************** 
This template trims the blanks from the left and right sides of a string. 
***************************************************************************************** 
--> 
<xsl:template name="all-trim"> 
    <!-- The string that you want to all trim. --> 
    <xsl:param name="inStr"/> 
    <xsl:param name="upperCase" select="false()"/> 

    <xsl:variable name="leftTrimmed"> 
    <xsl:call-template name="left-trim"> 
     <xsl:with-param name="inStr" select="$inStr"/> 
    </xsl:call-template> 
    </xsl:variable> 

    <xsl:variable name="rightTrimmed"> 
    <xsl:call-template name="right-trim"> 
     <xsl:with-param name="inStr" select="$leftTrimmed"/> 
    </xsl:call-template> 
    </xsl:variable> 

    <xsl:choose> 
    <xsl:when test="$upperCase"> 
     <xsl:value-of select="translate($rightTrimmed, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/> 
    </xsl:when> 
    <xsl:otherwise> 
     <xsl:value-of select="$rightTrimmed"/> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

<!-- 
***************************************************************************************** 
This template trims the blanks from the left side of a string. 
***************************************************************************************** 
--> 
<xsl:template name="left-trim"> 
    <!-- The string you want to left trim. --> 
    <xsl:param name ="inStr"/> 

    <xsl:choose> 
    <xsl:when test="$inStr!=''"> 
     <xsl:variable name="temp" select="substring($inStr, 1, 1)"/> 
     <xsl:choose> 
     <xsl:when test="$temp=' '"> 
      <xsl:choose> 
      <xsl:when test="string-length($inStr) &gt; 1"> 
       <xsl:call-template name="left-trim"> 
       <xsl:with-param name="inStr" select="substring($inStr, 2, string-length($inStr)-1)"/> 
       </xsl:call-template> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:value-of select="''"/> 
      </xsl:otherwise> 
      </xsl:choose> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:value-of select="$inStr"/> 
     </xsl:otherwise> 
     </xsl:choose> 
    </xsl:when> 
    <xsl:otherwise> 
     <xsl:value-of select="''"/> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 


<!-- 
***************************************************************************************** 
This template trims the blanks from the right side of a string. 
***************************************************************************************** 
--> 
<xsl:template name="right-trim"> 
    <!-- The string you want to right trim. --> 
    <xsl:param name ="inStr"/> 

    <xsl:choose> 
    <xsl:when test="$inStr!=''"> 
     <xsl:variable name="temp" select="substring($inStr, string-length($inStr), 1)"/> 
     <xsl:choose> 
     <xsl:when test="$temp=' '"> 
      <xsl:choose> 
      <xsl:when test="string-length($inStr) &gt; 1"> 
       <xsl:call-template name="right-trim"> 
       <xsl:with-param name="inStr" select="substring($inStr, 1, string-length($inStr)-1)"/> 
       </xsl:call-template> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:value-of select="''"/> 
      </xsl:otherwise> 
      </xsl:choose> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:value-of select="$inStr"/> 
     </xsl:otherwise> 
     </xsl:choose> 
    </xsl:when> 
    <xsl:otherwise> 
     <xsl:value-of select="''"/> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 
Cuestiones relacionadas