sanjay
sanjay

Reputation: 1020

XSLT - add new node between numbers and text between content text

Is it possible in xslt to add new node between numbers and text within content text.

as example :

<doc>
  <a>1 Available accessibility features for....</a>
  <b>..between two teams of 11 players each on a..</b>
  <c>The game is played by 120 million players..</c>
</doc>

I need to add <s> node between numbers and text between above xml. so the output xml should be

<doc>
  <a>1<s/> Available accessibility features for....</a>
  <b>..between two teams of<s/> 11<s/> players each on a..</b>
  <c>The game is played by <s/>120<s/> million  players..</c>
</doc>

I tried hard find any method how can do this task but unable find any good solution. is there any possible way of do this in xslt ?

Upvotes: 1

Views: 123

Answers (2)

Ian Roberts
Ian Roberts

Reputation: 122394

This is a simplification of Martin's answer. The way analyze-string works is to split the input string into a sequence of matching and non-matching substrings and use the appropriate handler for each. Within a (non-)matching-substring handler, the position() function is the position of this substring within the list of substring chunks and last() is the total number of matching and non-matching substrings. Thus you can use a much simpler regex that just matches the digits, and use position() to deal with the end effects:

<xsl:analyze-string select="." regex="[0-9]+">
  <xsl:matching-substring>
    <xsl:if test="position() gt 1">
      <s/>
    </xsl:if>
    <xsl:value-of select="." />
    <xsl:if test="position() lt last()">
      <s/>
    </xsl:if>
  </xsl:matching-substring>
  <xsl:non-matching-substring>
    <xsl:value-of select="." />
  </xsl:non-matching-substring>
</xsl:analyze-string>

The first if is true if there was a non-matching substring before this matching substring, the second if is true if there is at least one non-matching substring still to go following the current matching one (while it's not necessarily the case in general, for this particular regex we can guarantee that matching and non-matching substrings will strictly alternate. It's not possible to get two matching substrings next to each other with a greedy + quantifier).

Upvotes: 1

Martin Honnen
Martin Honnen

Reputation: 167696

As already suggested, this is a job for analyze-string. The stylesheet

<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="@* | node()">
  <xsl:copy>
    <xsl:apply-templates select="@* , node()"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="text()" priority="5">
  <xsl:analyze-string select="." regex="(^|[^0-9]+)([0-9]+)([^0-9]+|$)">
    <xsl:matching-substring>
      <xsl:if test="string-length(regex-group(1)) gt 0">
        <xsl:value-of select="regex-group(1)"/>
        <s/>
      </xsl:if>
      <xsl:value-of select="regex-group(2)"/>
      <xsl:if test="string-length(regex-group(3)) gt 0">
        <s/>
        <xsl:value-of select="regex-group(3)"/>
      </xsl:if>
    </xsl:matching-substring>
    <xsl:non-matching-substring>
      <xsl:value-of select="."/>
    </xsl:non-matching-substring>
  </xsl:analyze-string>
</xsl:template>

</xsl:stylesheet>

transforms

<doc>
  <a>1 Available accessibility features for....</a>
  <b>..between two teams of 11 players each on a..</b>
  <c>The game is played by 120 million players..</c>
</doc>

into

<doc>
  <a>1<s/> Available accessibility features for....</a>
  <b>..between two teams of <s/>11<s/> players each on a..</b>
  <c>The game is played by <s/>120<s/> million players..</c>
</doc>

Upvotes: 3

Related Questions