Search

Has anyone written an XSLT utility that selects the first letter (or first two letters if they have an open quote or double quote) of text in a text editor and wraps it in a span tag so you can style a drop cap?

I want to only apply it if the text starts with a paragraph.

I have something ugly working, but it fails when I have any sort of node inside the paragraph like <em>, <strong> or <a>.

I basically want to take:

 <story-content>
      <copy>
           <p>Class aptent <a href="#">taciti sociosqu ad litora</a> torquent per conubia nostra, per inceptos himenaeos. Duis eget placerat risus. Aenean adipiscing, metus convallis sollicitudin mollis, leo lacus porttitor odio, eu facilisis ante lacus sit amet felis. Sed vitae mauris est. Nullam at tempor sapien. Morbi vel nisi ut orci condimentum feugiat at aliquet nulla. Sed iaculis neque sed mauris accumsan tincidunt. Quisque diam eros, aliquet pulvinar condimentum a, tristique sed erat. Cras id rutrum ipsum.</p>
           <h3>Heading 3</h3>
           <p>Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis eget placerat risus. Aenean adipiscing, metus convallis sollicitudin mollis, leo lacus porttitor odio, eu facilisis ante lacus sit amet felis. Sed vitae mauris est. Nullam at tempor sapien. Morbi vel nisi ut orci condimentum feugiat at aliquet nulla. Sed iaculis neque sed mauris accumsan tincidunt. Quisque diam eros, aliquet pulvinar condimentum a, tristique sed erat. Cras id rutrum ipsum.</p>
      </copy>
 </story-content>

And add the span “dropcap” in the HTML output:

 <p><span class="dropcap">C</span>lass aptent <a href="#">taciti sociosqu ad litora</a> torquent per conubia nostra, per inceptos himenaeos. Duis eget placerat risus. Aenean adipiscing, metus convallis sollicitudin mollis, leo lacus porttitor odio, eu facilisis ante lacus sit amet felis. Sed vitae mauris est. Nullam at tempor sapien. Morbi vel nisi ut orci condimentum feugiat at aliquet nulla. Sed iaculis neque sed mauris accumsan tincidunt. Quisque diam eros, aliquet pulvinar condimentum a, tristique sed erat. Cras id rutrum ipsum.</p>
 <h3>Heading 3</h3>
 <p>Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis eget placerat risus. Aenean adipiscing, metus convallis sollicitudin mollis, leo lacus porttitor odio, eu facilisis ante lacus sit amet felis. Sed vitae mauris est. Nullam at tempor sapien. Morbi vel nisi ut orci condimentum feugiat at aliquet nulla. Sed iaculis neque sed mauris accumsan tincidunt. Quisque diam eros, aliquet pulvinar condimentum a, tristique sed erat. Cras id rutrum ipsum.</p>

Thanks!

Blah! my post won’t show up.

Fixed it for you, had to wrap <em>, <strong> and <a> with back-ticks.

Thanks for the fix.

I just came across another time when I’d need to wrap the first two letters in the span tag. If the first character is followed by punctuation.

 <p><span class="dropcap">A.</span> Anderson does blah, blah, blah ...</p>

Arg!

I think JavaScript will be the way to go with this. :-(

Doesn’t CSS :first-letter work? :-)

Doesn’t CSS :first-letter work? :-)

Browser support isn’t great

Browser support isn’t great

Looks good to me. :-)

What about…

<xsl:template match="story-content/copy/p">
    <p>
        <xsl:apply-templates />
    </p>
</xsl:template>

<xsl:template match="story-content/copy/*">
       <xsl:copy-of select="." />
</xsl:template>

<xsl:template match="story-content/copy/p/*">
       <xsl:copy-of select="." />
</xsl:template>

<xsl:template match="story-content/copy/p/text()">
       <xsl:value-of select="." />
</xsl:template>

<xsl:template match="data/item/p[1]/text()[1]">
   <xsl:variable name="body" select="normalize-space(.)"/>
   <xsl:choose>
    <xsl:when test="substring($body,2,1) = '.'">
        <span class="dropcap"><xsl:value-of select="substring($body,0,3)" /></span>
        <xsl:copy-of select="substring($body,3)" />
    </xsl:when>
    <xsl:otherwise>
        <span class="dropcap"><xsl:value-of select="substring($body,0,2)" /></span>
        <xsl:copy-of select="substring($body,2)" />
    </xsl:otherwise>
   </xsl:choose>
</xsl:template> 

I suspect there will be a more compact solution to this…

Looks good to me. :-)

I stand corrected! For some reason, I thought this was one of those pseudo-classes that wasn’t too widely supported.

Looks good to me. :-)

Me too. I didn’t try it because of the assumption. I wonder how it handles punctuation … I’ll have to test. Thanks for the input.

selector > doesn’t work with IE6. That’s usually how people select the first paragraph and then the first letter with :first-letter.

I tested :first-letter and it handles punctuation before the letter just fine, but fails to include punctuation after.

:first-letter also has some design problems. You can read about them here. It may be nit-picky, but that’s how I get sometimes. :-)

Since this is a presentational thing, I’m going to try this jQuery thing next and see how that works.

If that’s a fail, I’ll start with the approach phoque posted above.

The XSLT snippet will now recognise punctuation: Lorem Ipsum becomes <span>L</span>orem ipsum and L. is a cute dog becomes <span>L.</span> is a cute dog.

After a lot of playing around, I have decided that

 p:first-child:first-letter { font-weight:bold; float:left; line-height:.8; font-size:5.4em; margin:.05em .08em 0 0; }

works beautifully and only IE6 doesn’t work (don’t care about IE6 anyway).

…only IE6 doesn’t work (don’t care about IE6 anyway).

You could give your first p a class using XSLT, superseding the need for :first-child (the only thing that breaks IE).

Edit: Now that I wrote it I am pretty sure you knew that. Ignore me. :-)

Create an account or sign in to comment.

Symphony • Open Source XSLT CMS

Server Requirements

  • PHP 5.3-5.6 or 7.0-7.3
  • PHP's LibXML module, with the XSLT extension enabled (--with-xsl)
  • MySQL 5.5 or above
  • An Apache or Litespeed webserver
  • Apache's mod_rewrite module or equivalent

Compatible Hosts

Sign in

Login details