tags:

views:

710

answers:

3

I need to programatically replace "regular double quotes" with typographer's quotes

My initial thought is something like this:

     <xsl:variable name="text">
      <xsl:call-template name="replace-string"><!-- FYI: replace-string is a custom method that works like you would expect-->
       <xsl:with-param name="text" select="."/>
       <xsl:with-param name="replace" select="string(' &quot;')" /><!-- left quote because of space before -->
       <xsl:with-param name="with" select="string('“')"/>
      </xsl:call-template>
     </xsl:variable>

     <xsl:variable name="text2">
      <xsl:call-template name="replace-string">
       <xsl:with-param name="text" select="$text"/>
       <xsl:with-param name="replace" select="string('&quot; ')" /><!-- right quote because of space after -->
       <xsl:with-param name="with" select="string('”')"/>
      </xsl:call-template>
     </xsl:variable>

     <xsl:apply-templates select="$text2" />

My worry is situations where there is not a determining space by the quote. Such as these.

They say "this is great". I like tigers ("big large cats").

Has anyone ever had to do this before that knows some extra rules to apply or a different strategy?

Thanks!

+1  A: 

Regular Expressions.

regex:replace($textVariable, '&quot;([^&quot;]*)&quot;' , 'gi', '“$1”')

Havent tested this, but this is an easy approach IMHO. you match all "(anything not ")zero or more times" and replace that with your other typographical quotes. The $1 is a back-reference to the first match. While there are issues here such as incorrectly nested text, quotes that are not closed etc., I am suggesting something like this. You may rewrite the regex for this one and test it out.

This is assuming that your XSLT processor supports the EXSLT extensions.

Thiyagaraj
Thanks for the help! That regedit seems to work when I test it in regulator.
joe
Regex (regular expression), not regedit (registry editor)!
Eric
+2  A: 

A solution that works without extension functions would be:

<xsl:template name="typograpic-quotes">
  <xsl:param name="text"    select="''" />
  <xsl:param name="quote"   select="'&quot;'" />
  <xsl:param name="open"    select="'“'" />
  <xsl:param name="close"   select="'”'" />
  <xsl:param name="inquote" select="false()" />

  <xsl:choose>
    <xsl:when test="contains($text, $quote)">
      <xsl:value-of select="substring-before($text, $quote)" />
      <xsl:choose>
        <xsl:when test="$inquote">
          <xsl:value-of select="$close" />
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="$open" />
        </xsl:otherwise>
      </xsl:choose>
      <xsl:call-template name="typograpic-quotes">
        <xsl:with-param name="text"    select="substring-after($text, $quote)" />
        <xsl:with-param name="quote"   select="$quote" />
        <xsl:with-param name="open"    select="$open" />
        <xsl:with-param name="close"   select="$close" />
        <xsl:with-param name="inquote" select="not($inquote)" />
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$text" />
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

Needless to say that unbalanced quotes in the input will make this fail.

Tomalak
Thanks for the help!
joe
A: 

Because we have some unbalanced quotes. I am working on something a little more pragmatic. The below seems to work in all cases I have tried.

 <!-- Get text.  All quotes defaulted to right quote -->
     <xsl:variable name="text">
      <xsl:call-template name="replace-string">
       <xsl:with-param name="text" select="."/>
       <xsl:with-param name="replace" select="string('&quot;')" />
       <xsl:with-param name="with" select="string('”')"/>
      </xsl:call-template>
     </xsl:variable>

     <!-- Turn quotes preceded by a space into left quote -->
     <xsl:variable name="text2">
      <xsl:call-template name="replace-string">
       <xsl:with-param name="text" select="$text"/>
       <xsl:with-param name="replace" select="string(' ”')" />
       <!-- right quote because of space after -->
       <xsl:with-param name="with" select="string(' “')"/>
      </xsl:call-template>
     </xsl:variable>

     <!-- Turn quotes preceded by a parenthesy into left quote -->
     <xsl:variable name="text3">
      <xsl:call-template name="replace-string">
       <xsl:with-param name="text" select="$text2"/>
       <xsl:with-param name="replace" select="string('(”')" />
       <!-- right quote because of space after -->
       <xsl:with-param name="with" select="string('(“')"/>
      </xsl:call-template>
     </xsl:variable>

     <!-- Turn quotes that are the first character in the text into left quote -->
     <!-- Note: this one is still a little funky. For some reason the first character is always whitespace.  So I am checking the second character because it is really the first. -->
     <xsl:variable name="text4" >
      <xsl:choose>
       <xsl:when test="normalize-space(substring( $text3, 2, 2 )) = string('”')">
        <xsl:value-of select="string('“')"/>
        <xsl:value-of select="substring($text3, 3)"/>
       </xsl:when>
       <xsl:otherwise>
        <xsl:value-of select="$text3"/>
       </xsl:otherwise>
      </xsl:choose>
     </xsl:variable>

     <xsl:apply-templates select="$text4" />
joe
Any feedback would be appreciated
joe