1

By using xsl template, can any one tell me the way to get first number portion of a string field

For example:

'12' -> should result in -> 12 '5 ASDF' -> should result in -> 5 '34SDF56' -> should result in -> 34 
4
  • 1
    What version of XSL are you using? What XSL processor? Commented Nov 15, 2010 at 15:47
  • I am using version 1.0 and cooktop... Commented Nov 15, 2010 at 15:56
  • see my general solution. Commented Nov 15, 2010 at 19:06
  • Good question, +1. See my answer for the shortest solution :) Commented Nov 15, 2010 at 19:56

3 Answers 3

4

Here is a one-liner XPath solution: :)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:template match="text()"> <xsl:variable name="vS" select="concat(.,'Z')"/> <xsl:value-of select= "substring-before(translate($vS,translate($vS,'0123456789',''),'Z'),'Z')"/> <xsl:text>&#xA;</xsl:text> </xsl:template> </xsl:stylesheet> 

when this transformation is applied on the following XML document:

<t> <x>12</x> <x>5 ASDF</x> <x>34SDF56</x> </t> 

the wanted, correct results are produced:

12 5 34 
Sign up to request clarification or add additional context in comments.

5 Comments

@Alejandro and @LarsH: I think you'd be interested to see this solution :)
why do you append the Z character to the string? Why can't use just use the value of the text node?
@Peter-Jacoby: This expression works OK for strings that start with digits followed by nondigit(s). If the string contains only digits, the empty string will be returned as result. This is way I append a 'Z' to the string before I process it.
thanks for the tag. Good point, the concat-Z helps make the code tighter: fewer conditionals... again, at the cost of readability. I also wonder about the potential cost of creating more, immutable strings. Nice trick, translating all non-numerics to 'Z' via a translated second argument to translate(). :-)
+1 Good answer. It could be also substring-before($vS,substring(translate($vS,'0123456789',''),1,1)) preserving the meaning "the string before first not digit" and ussing three functions calls.
1

you could give this a go? should work supposing that you know the maximum length of numbers!

so here you could find a number upto 6 digits long! hope it helps

 <xsl:variable name="YourString" select="YourStringPath"/> <xsl:choose> <xsl:when test="substring($YourString,1,6) &gt; 0"> <xsl:value-of select="substring($YourString,1,6)"/> </xsl:when> <xsl:when test="substring($YourString,1,5) &gt; 0"> <xsl:value-of select="substring($YourString,1,5)"/> </xsl:when> <xsl:when test="substring($YourString,1,4) &gt; 0"> <xsl:value-of select="substring($YourString,1,4)"/> </xsl:when> <xsl:when test="substring($YourString,1,3) &gt; 0"> <xsl:value-of select="substring($YourString,1,3)"/> </xsl:when> <xsl:when test="substring($YourString,1,2) &gt; 0"> <xsl:value-of select="substring($YourString,1,2)"/> </xsl:when> <xsl:when test="substring($YourString,1,1) &gt; 0"> <xsl:value-of select="substring($YourString,1,1)"/> </xsl:when> <xsl:otherwise>default number here?</xsl:otherwise> </xsl:choose> 

2 Comments

Thank you for the reply, this solution works and I needed upto 5 numbers, so I can easily amend your code to get up to 5 numbers by eliminating the first when statement.
Now I need the remaining string without leading spaces. For example I want '5 ASDF' to return 'ASDF', and '12ASDF 34' to return 'ASDF 34'.
0

The following template will emit all numeric digits of a string up to the first non-numeric (without having to know how many digits may be in the number):

 <xsl:template match="@num"> <xsl:variable name="nonNumbers" select="translate(., '0123456789', '')"/> <xsl:attribute name="{name()}"> <xsl:choose> <xsl:when test="$nonNumbers"> <xsl:value-of select="substring-before(., substring($nonNumbers, 1, 1))" /> </xsl:when> <xsl:otherwise> <xsl:value-of select="."/> </xsl:otherwise> </xsl:choose> </xsl:attribute> </xsl:template> 

(Thanks to @Alejandro for the key idea, using substring() to get the first non-number, and then passing it to substring-before().) Here it is in the context of an identity transform:

<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:template match="@num"> <xsl:variable name="nonNumbers" select="translate(., '0123456789', '')"/> <xsl:attribute name="{name()}"> <xsl:choose> <xsl:when test="$nonNumbers"> <xsl:value-of select="substring-before(., substring($nonNumbers, 1, 1))" /> </xsl:when> <xsl:otherwise> <xsl:value-of select="."/> </xsl:otherwise> </xsl:choose> </xsl:attribute> </xsl:template> <!-- Identity transform --> <xsl:template match="@* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet> 

When run on the following input:

<?xml version="1.0" encoding="UTF-8"?> <values> <value num="12"/> <value num="5 ASDF"/> <value num="34SDF56"/> </values> 

it produces the requested output:

<?xml version="1.0" encoding="utf-8"?> <values> <value num="12"/> <value num="5"/> <value num="34"/> </values> 

Another way to do the @num template is the following, arguably more elegant but harder to read IMO:

 <xsl:template match="@num[translate(., '0123456789', '') = '']"> <!-- alternatively, match="@num[number(.) > 0]" --> <xsl:copy /> </xsl:template> <xsl:template match="@num"> <xsl:attribute name="{name()}"> <xsl:value-of select="substring-before(., substring( translate(., '0123456789', ''), 1, 1))" /> </xsl:attribute> </xsl:template> 

Notes:

  • The first of the two @num templates above takes priority over the second, because the first is more specific, having a predicate. So the first template is used to process @num's that it matches, and the second template processes all other @num's.
  • The first template matches @num's whose value is all digits, and merely copies the attribute. If we didn't make this exception, the second template would output empty string values for such @num's.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.