1

I am stuck in a problem where I need to add commas in a string after certain words. For eg. the string is:

String1 : My name is John Smith I have a bat its costs is $150

String2 : My name is Michael Dawson I have a bike its costs is $10000

To convert into

String1 : My name is John Smith, I have a dog, its costs is $100

String2 : My name is Michael Dawson, I have a bike, its costs is $10000

I reckon we need to count the spaces using string-length but how to replace the spaces after 5th/9th space with a comma?

Please suggest

Thanks

Community
  • 1
  • 1
user2128585
  • 47
  • 2
  • 10
  • To place a comma in a grammatically sensible position is not going to be trivial (e.g. `My full name is John, Smith I have, a bat...`) – StuartLC Oct 27 '14 at 06:23
  • Idea is to identify a way to add something after a certain number of words, ignoring grammer for this case. – user2128585 Oct 27 '14 at 06:31

2 Answers2

1

You can define a named template add_character_at_position that inserts one character at a given position as follows:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet 
    version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />

  <xsl:template match="data">
    <result>
      <xsl:for-each select="string">
        <string>
          <xsl:call-template name="add_character_at_position">
            <xsl:with-param name="string" select="."/>
            <xsl:with-param name="position" select="@pos"/>
          </xsl:call-template>
        </string>
      </xsl:for-each>
    </result>
  </xsl:template>

  <xsl:template name="add_character_at_position_recurse">
    <xsl:param name="prefix"/>
    <xsl:param name="suffix"/>
    <xsl:param name="position"/>
    <xsl:param name="char"/>
    <xsl:param name="seperator"/>

    <xsl:choose>

      <xsl:when test="$position = 0">
        <xsl:value-of select="concat($prefix, $char, $suffix)"/>
      </xsl:when>

      <xsl:otherwise>
        <xsl:call-template name="add_character_at_position_recurse">
          <xsl:with-param name="prefix" select="concat($prefix, $seperator, substring-before(substring($suffix, 2), $seperator))"/>
          <xsl:with-param name="suffix" select="concat($seperator, substring-after(substring($suffix,2), $seperator))"/>
          <xsl:with-param name="position" select="$position - 1"/>
          <xsl:with-param name="char" select="$char"/>
          <xsl:with-param name="seperator" select="$seperator"/>
        </xsl:call-template>
      </xsl:otherwise>
    </xsl:choose>

  </xsl:template>

  <xsl:template name="add_character_at_position">
    <xsl:param name="string"/>
    <xsl:param name="position"/>
    <xsl:param name="char" select="','"/>
    <xsl:param name="seperator" select="' '"/>

    <xsl:variable name="result">
      <xsl:call-template name="add_character_at_position_recurse">
        <xsl:with-param name="prefix" select="''"/>
        <xsl:with-param name="suffix" select="concat($seperator, $string)"/>
        <xsl:with-param name="position" select="$position"/>
      <xsl:with-param name="char" select="$char"/>
      <xsl:with-param name="seperator" select="$seperator"/>
      </xsl:call-template>
    </xsl:variable>

    <xsl:value-of select="substring($result, 2)"/>

  </xsl:template>

</xsl:stylesheet>

It uses recursion (as usual in XSLT 1.0) to split the string and insert the character between the current prefix and suffix. If you need several characters (commas) you will have to call this template nested several times. Note that the template currently does not any checking whether the position parameter is valid.

The test setup used the following input XML:

<?xml version="1.0" encoding="ISO-8859-1"?>
<data>
  <string pos="5">My name is John Smith I have a bat its costs is $150</string>
</data>

Generating the following result:

<?xml version="1.0" encoding="UTF-8"?>
<result>
  <string>My name is John Smith, I have a bat its costs is $150</string>
</result>
Marcus Rickert
  • 4,138
  • 3
  • 24
  • 29
0

Thanks Marcus, really appreciate your reply.

I found another way, by using tokenize. And then again run for loop to put seperators afters specific number of words.For e.g

        <xsl:for-each select="tokenize(text,' ')">
            <word>
                <xsl:value-of select="normalize-space(.)"/>
            </word>
        </xsl:for-each>
user2128585
  • 47
  • 2
  • 10