1

lets suppose I have an xml like

<Fractions>
<Fraction>test 1/3 test aaa</Fraction>
<Fraction>1/2 test</Fraction>
</Fractions>

I want to replace 1/3 with &amp;frac13, 1/2 with @amp;frac12 which is in the string using xsl but I am stuck. The fraction values are limited like

1/2, 1/3, 3/4, 1/4. 
8
  • Are 1/3 and 1/2 the only fractions that are going to appear in your XML, or are you going have a much greater number of fractions? Commented Aug 1, 2011 at 7:45
  • There could be greater num of fractions Commented Aug 1, 2011 at 8:39
  • 1
    Is there going to be an upper limit on the size of the fractions though, or could you have fractions like 1/1000000? Commented Aug 1, 2011 at 8:40
  • 1
    This is a "number to word" as an example (never tested, just immediate googling). You will need to expand this to a "fraction to word". I think I would not answer this even for a +50 bounty, may be a +500. Commented Aug 1, 2011 at 10:00
  • there are fractions only like 1/2, 1/4, 1/3 to be replaced Commented Aug 1, 2011 at 10:31

2 Answers 2

1

If you can guarantee that the input XML will only have single digits, you could achieve this with simple look-up tables, which return the name of either the cardinal number (one, two, three, etc) or the ordinal form of the number (Half, Third, Fourth, etc)

   <ref:cardinals>
      <ref:cardinal>One</ref:cardinal>
      <ref:cardinal>Two</ref:cardinal>
      <ref:cardinal>Three</ref:cardinal>
      ... and so on...
   </ref:cardinals>

   <ref:ordinals>
      <ref:ordinal>Half</ref:ordinal>
      <ref:ordinal>Third</ref:ordinal>
      ... and so on ...
   </ref:ordinals>

(Where the ref namespace would have to be declared at the top of the XSLT)

To look up values in these look-up tables, you could set up a variable which references the XSLT document itself

<xsl:variable name="cardinals" select="document('')/*/ref:cardinals"/>
<xsl:value-of select="$cardinals/ref:cardinal[position() = $numerator]"/>

(Where $numerator is a variable containing the top half of the fraction)

Here is a full XSLT document which can cope with all single digit fractions

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ref="http://stackoverflow.com/users/723763/abdul-muqtadir">
   <xsl:output method="xml" indent="yes"/>

   <ref:cardinals>
      <ref:cardinal>One</ref:cardinal>
      <ref:cardinal>Two</ref:cardinal>
      <ref:cardinal>Three</ref:cardinal>
      <ref:cardinal>Four</ref:cardinal>
      <ref:cardinal>Five</ref:cardinal>
      <ref:cardinal>Six</ref:cardinal>
      <ref:cardinal>Seven</ref:cardinal>
      <ref:cardinal>Eight</ref:cardinal>
      <ref:cardinal>Nine</ref:cardinal>
   </ref:cardinals>

   <ref:ordinals>
      <ref:ordinal>Half</ref:ordinal>
      <ref:ordinal>Third</ref:ordinal>
      <ref:ordinal>Quarter</ref:ordinal>
      <ref:ordinal>Fifth</ref:ordinal>
      <ref:ordinal>Sixth</ref:ordinal>
      <ref:ordinal>Seventh</ref:ordinal>
      <ref:ordinal>Eigth</ref:ordinal>
      <ref:ordinal>Ninth</ref:ordinal>
   </ref:ordinals>

   <xsl:variable name="cardinals" select="document('')/*/ref:cardinals"/>
   <xsl:variable name="ordinals" select="document('')/*/ref:ordinals"/>

   <xsl:template match="Fraction">
      <xsl:variable name="numerator" select="number(substring-before(., '/'))"/>
      <xsl:variable name="denominater" select="number(substring-after(., '/'))"/>
      <xsl:copy>
         <xsl:value-of select="$cardinals/ref:cardinal[position() = $numerator]"/>
         <xsl:text> </xsl:text>
         <xsl:value-of select="$ordinals/ref:ordinal[position() = $denominater - 1]"/>
         <xsl:if test="$numerator != 1">s</xsl:if>
      </xsl:copy>
   </xsl:template>

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

When applied to your input XML, the following XML is returned

<Fractions>
   <Fraction>One Third</Fraction>
   <Fraction>One Half</Fraction>
</Fractions>

Note that you may have to look at handling plurals better. For example, if you had 3/2 as a fraction, the above solution returns Three Halfs, and not Three Halves.

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

1 Comment

I am really grateful to your answer. What if I want to replace 1/3 to '&amp;frac13;' 3/4 to '&amp;frac34;' and so and so.
0

If there's only a few, then use templates like these:

<xsl:template match="Fraction/text()[.='1/2']">half</xsl:template>
<xsl:template match="Fraction/text()[.='1/3']">one-third</xsl:template>
etc..

3 Comments

The xsl is like <xsl:stylesheet xmlns:xsl="w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml" omit-xml-declaration="yes"/> <xsl:template match="Fraction/text()[.='1/2']">&amp;frac12;</xsl:template> <xsl:template match="Fraction/text()[.='1/3']">&amp;frac13;</xsl:template> </xsl:stylesheet> but its not replacing 1/2 or 1/3 if present in xml
Oh, the text is WITHIN other text? Sorry, by your example it looked like 1/2 or 1/3 was the entire content of the node. In that case you need a recursive text-replace template. There's probably numerous examples on SO.
If you could put a solution, that would be a great help.

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.