44

I have a string in a node and I'd like to split the string on '?' and return the last item in the array.

For example, in the block below:

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

I'd like to split the someNode value.

Edit: Here's the VB.Net that I use to load the Xsl for my Asp.Net page:

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

Update: here's an example of splitting XML on a particular node

1
  • 4
    Does not really have anything to do with ASP.Net Commented Nov 10, 2009 at 12:34

8 Answers 8

51

Use a recursive method:

<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>
Sign up to request clarification or add additional context in comments.

2 Comments

Note that if there are no tokens in the list, this template will nevertheless output an empty <id> element, instead of no <id> elements.
I was quite excited about trying this, but Firefox unfortunately says : "Error during XSLT transformation: XSLT Stylesheet (possibly) contains a recursion.". Yes, Firefox it's supposed to be recursive...duh...
12

If you can use XSLT 2.0 or higher, you can use tokenize(string, separator):

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

See the w3schools XPath function reference.

By default, .NET does not support XSLT 2.0, let alone XSLT 3.0. The only known 2.0+ processors for .NET are Saxon for .NET with IKVM, Exselt, a .NET XSLT 3.0 processor currently in beta, and XMLPrime XSLT 2.0 processor.

3 Comments

The only down-side is that it requires XSLT 2.0 :-(
yeah, i'm getting a "'tokenize()' is an unknown XSLT function." error
Which processor are you using?
8

I ended up using the substring-after() function. Here's what worked for me:

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

Even after setting the version of my XSLT to 2.0, I still got a "'tokenize()' is an unknown XSLT function." error when trying to use tokenize().

1 Comment

I wish I had kept the code, but at my previous employer I wrote a xslt 1.0 function to get the n-th token of a string. It's not too difficult once you wrap your head around the concept functional programming
6

Adding another possibility, if your template engine supports EXSLT, then you could use tokenize() from that.

For example:

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

1 Comment

Have you used this successfully in .net?
3

.NET doesn't support XSLT 2.0, unfortunately. I'm pretty sure that it supports EXSLT, which has a split() function. Microsoft has an older page on its implementation of EXSLT.

Comments

2

You can write a template using string-before and string-after functions and use it across. I wrote a blog on this.

Finally came up with a xslt template that would split a delimited string into substrings. I don’t claim it’s the smartest script, but surely solves my problem.

Stylesheet:

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

XML file (to be transformed) :

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

Comments

1

XSLT 1.0 doesn't have a split function per se, but you could potentially achieve what you're trying to do with the substring-before and substring-after functions.

Alternatively, if you're using a Microsoft XSLT engine, you could use inline C#.

Comments

1

Just for the record, if you're doing this with 1.0, and you really need a split/tokenise, you need the xslt extensions.

1 Comment

interesting, how would i use that in the example above?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.