0

i've the below xml

<para>A number of the offences set out in the Companies Ordinance are expressed to apply to "officers" of the company. "Officer" includes directors, managers and the company secretary: Companies Ordinance, s.2(1).</para>

here actually the in the input the quotes given are " but i want to convert it to smart quotes. i used the below xslt for this.

<xsl:template match="para/text()">
<xsl:when test="contains(.,$quot)">
<xsl:value-of select="translate(.,$quot,'“')"/>
<xsl:value-of select="translate(substring-after(.,$quot),$quot,'”')"/>
</xsl:when>
</xsl:template>

but i am getting below ooutput.

A number of the offences set out in the Companies Ordinance are expressed to apply to “officers“ of the company. “Officer“ includes directors, managers and the company secretary: Companies Ordinance, s.2(1).

but i want to get it as below.

A number of the offences set out in the Companies Ordinance are expressed to apply to “officers” of the company. “Officer” includes directors, managers and the company secretary: Companies Ordinance, s.2(1).

please let me know how do i solve this.

Thanks

4

1 回答 1

0

The main problem with your approach is that the translate function will replace all occurrences of the quotation mark with your smart-opening quote. Therefore, the subsequent substring-after function won't actually find anything because there won't be any more quotation marks to find.

What you really need in this case is a recursive template, together with a combination of both substring-before and substring-after. The named template could actually be combined with your existing template, with default parameters to be used in the initial match

   <xsl:template match="para/text()" name="replace">
      <xsl:param name="text" select="."/>
      <xsl:param name="usequote" select="$openquote"/>

($openquote will be a variable containing the opening quote)

You would then check if the selected text contains a quotation mark

<xsl:when test="contains($text,$quot)">

If so, you would first output the text before the quotation mark, following by the new open quote

<xsl:value-of select="concat(substring-before($text, $quot), $usequote)"/>

The template would then be recursively called with the text after the quote, and with the close quote as a parameter, so the next quote find will be closed.

<xsl:call-template name="replace">
   <xsl:with-param name="text" select="substring-after($text,$quot)"/>
   <xsl:with-param name="usequote"
         select="substring(concat($openquote, $closequote), 2 - ($usequote=$closequote), 1)"/>
</xsl:call-template>

Note: the selecting of the usequote will basically switch between open and close quotes. It takes advantage of the fact 'true' evaluates to 1 in a numeric expression, and 'false' to 0.

Try this XSLT. Note, I am using open and close brackets in this case, just to make the output clearer, but you can easily change the variables to your smart quotes as required. (You may have to specify an encoding for the output in this case though).

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
   <xsl:output method="text"/>

   <xsl:variable name="quot">"</xsl:variable>
   <xsl:variable name="openquote">[</xsl:variable>
   <xsl:variable name="closequote">]</xsl:variable>

   <xsl:template match="para/text()" name="replace">
      <xsl:param name="text" select="."/>
      <xsl:param name="usequote" select="$openquote"/>
      <xsl:choose>
         <xsl:when test="contains($text,$quot)">
            <xsl:value-of select="concat(substring-before($text, $quot), $usequote)"/>
            <xsl:call-template name="replace">
               <xsl:with-param name="text" select="substring-after($text,$quot)"/>
               <xsl:with-param name="usequote"
                    select="substring(concat($openquote, $closequote), 2 - ($usequote=$closequote), 1)"/>
            </xsl:call-template>
         </xsl:when>
         <xsl:otherwise>
            <xsl:value-of select="$text"/>
         </xsl:otherwise>
      </xsl:choose>
   </xsl:template>

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

When applied to your XML, the following is output

A number of the offences set out in the Companies Ordinance are expressed to apply to [officers] of the company. [Officer] includes directors, managers and the company secretary: Companies Ordinance, s.2(1).
于 2013-05-20T17:32:44.870 回答