2008-09-25 31 views
42

Tengo una cadena en un nodo y me gustaría dividir la cadena en '?' y devolver el último elemento de la matriz.¿XSLT tiene una función Split()?

Por ejemplo, en el bloque a continuación:

<a> 
    <xsl:attribute name="href"> 
     /newpage.aspx?<xsl:value-of select="someNode"/> 
    </xsl:attribute> 
    Link text 
</a> 

me gustaría dividir el valor someNode.

Editar: Aquí está la VB.Net que utilizo para cargar el XSL para mi página Asp.Net:

Dim xslDocPath As String = HttpContext.Current.Server.MapPath("~/App_Data/someXslt.xsl") 
Dim myXsltSettings As New XsltSettings() 
Dim myXMLResolver As New XmlUrlResolver() 

myXsltSettings.EnableScript = True 
myXsltSettings.EnableDocumentFunction = True 

myXslDoc = New XslCompiledTransform(False) 
myXslDoc.Load(xslDocPath, myXsltSettings, myXMLResolver) 

Dim myStringBuilder As New StringBuilder() 
Dim myXmlWriter As XmlWriter = Nothing 

Dim myXmlWriterSettings As New XmlWriterSettings() 
myXmlWriterSettings.ConformanceLevel = ConformanceLevel.Auto 
myXmlWriterSettings.Indent = True 
myXmlWriterSettings.OmitXmlDeclaration = True 

myXmlWriter = XmlWriter.Create(myStringBuilder, myXmlWriterSettings) 

myXslDoc.Transform(xmlDoc, argumentList, myXmlWriter) 

Return myStringBuilder.ToString() 

Actualización: aquí estáan example of splitting XML on a particular node

+3

en realidad no tiene nada que ver con ASP.Net – Ikke

Respuesta

51

usar un método recursivo:

<xsl:template name="output-tokens"> 
    <xsl:param name="list" /> 
    <xsl:variable name="newlist" select="concat(normalize-space($list), ' ')" /> 
    <xsl:variable name="first" select="substring-before($newlist, ' ')" /> 
    <xsl:variable name="remaining" select="substring-after($newlist, ' ')" /> 
    <id> 
     <xsl:value-of select="$first" /> 
    </id> 
    <xsl:if test="$remaining"> 
     <xsl:call-template name="output-tokens"> 
      <xsl:with-param name="list" select="$remaining" /> 
     </xsl:call-template> 
    </xsl:if> 
</xsl:template> 
+0

Funcionó como un encanto. ¡Gracias! –

+42

Código impresionante. Solo me recordó cuánto odio el XSLT. – Jules

+2

Tenga en cuenta que si no hay tokens en la lista, esta plantilla dará como resultado un elemento vacío '', en lugar de ningún elemento ''. – LarsH

11

Si puede utilizar XSLT 2.0 o superior, puede utilizar tokenize(string, separator):

tokenize("XPath is fun", "\s+") 
Result: ("XPath", "is", "fun") 

Véase el w3schools XPath function reference.

De forma predeterminada, .NET no es compatible con XSLT 2.0, y mucho menos con XSLT 3.0. Los únicos procesadores 2.0+ conocidos para .NET son Saxon for .NET con IKVM, Exselt, un procesador .NET XSLT 3.0 actualmente en beta y XMLPrime procesador XSLT 2.0.

+4

El único inconveniente es que requiere XSLT 2.0 :-( –

+1

Sí, estoy obteniendo un "'tokenize()' es una función XSLT desconocida." Error – travis

+0

¿Qué procesador estás usando? –

1

XSLT 1.0 no tiene una función dividida per se, pero podría lograr lo que está tratando de hacer con las funciones de subcadena antes y subcadena posterior.

Alternativamente, si está utilizando un motor Microsoft XSLT, puede usar C# en línea.

8

Terminé usando la función substring-after(). Esto es lo que funcionó para mí:

<a> 
    <xsl:attribute name="href"> 
     /newpage.aspx?<xsl:value-of select="substring-after(someNode, '?')"/> 
    </xsl:attribute> 
    Link text 
</a> 

Incluso después de ajustar la versión de mi XSLT a 2,0, todavía tengo un "'tokenize()' is an unknown XSLT function." error al intentar utilizar tokenize().

+0

Ojalá hubiera conservado el código, pero una t mi empleador anterior escribí una función xslt 1.0 para obtener la n-ésima señal de una cadena. No es demasiado difícil una vez que te encierres en el concepto de programación funcional – Moe

1

Solo para el registro, si está haciendo esto con 1.0, y realmente necesita una división/tokenización, necesita el xslt extensions.

+0

interesante, ¿cómo usaría eso en el ejemplo anterior? – travis

3

.NET no admite XSLT 2.0, por desgracia. Estoy bastante seguro de que es compatible con EXSLT, que tiene una función split(). Microsoft tiene un older page en su implementación de EXSLT.

6

Añadiendo otra posibilidad, si su motor de plantilla admite EXSLT, entonces podría usar tokenize() desde allí.

Por ejemplo:

<xsl:stylesheet version="1.0" 
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
       xmlns:str="http://exslt.org/strings" 
       extension-element-prefixes="str"> 

... 
    <a> 
    <xsl:attribute name="href"> 
     <xsl:text>/newpage.aspx?</xsl:text> 
     <xsl:value-of select="str:tokenize(someNode)[2]"/> 
    </xsl:attribute>    
    </a> 
... 
</xsl:stylesheet> 
+0

¿Lo usaste con éxito en .net? – travis

+0

@travis: No, no uso .net ... –

2

puede escribir una plantilla usando string-before y string-after funciones y utilizarlo a través. Escribí un blog en esto.

Finalmente apareció una plantilla xslt que dividiría una cadena delimitada en subcadenas. No pretendo que sea la secuencia de comandos más inteligente, pero seguramente resuelve mi problema.

de estilos:

<?xml version="1.0" encoding="iso-8859-1"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:template match="/"> 
<xsl:for-each select="Paths/Item"> 
<xsl:call-template name="SplitText"> 
<xsl:with-param name="inputString" select="Path"/> 
<xsl:with-param name="delimiter" select="Delimiter"/> 
</xsl:call-template> 
<br/> 
</xsl:for-each> 
</xsl:template> 
<xsl:template name="SplitText"> 
<xsl:param name="inputString"/> 
<xsl:param name="delimiter"/> 
<xsl:choose> 
<xsl:when test="contains($inputString, $delimiter)"> 
<xsl:value-of select="substring-before($inputString,$delimiter)"/> 
<xsl:text disable-output-escaping = "no"> </xsl:text> 
<xsl:call-template name="SplitText"> 
<xsl:with-param name="inputString" select="substring-after($inputString,$delimiter)"/> 
<xsl:with-param name="delimiter" select="$delimiter"/> 
</xsl:call-template> 
</xsl:when> 
<xsl:otherwise> 
<xsl:choose> 
<xsl:when test="$inputString = ''"> 
<xsl:text></xsl:text> 
</xsl:when> 
<xsl:otherwise> 
<xsl:value-of select="$inputString"/> 
<xsl:text> </xsl:text> 
</xsl:otherwise> 
</xsl:choose> 
</xsl:otherwise> 
</xsl:choose> 
</xsl:template> 
</xsl:stylesheet> 

archivo XML (para ser transformados):

<?xml version="1.0" encoding="utf-8"?> 
<?xml-stylesheet type="text/xsl" href="textSpliter.xslt"?> 
<Paths> 
    <Item> 
    <Path>C:\ProgramFiles\SomeWierdSoftware</Path> 
    <Delimiter>\</Delimiter> 
    </Item> 
</Paths>