You could cut it down a fair bit by using literal result elements, and putting the stuff that doesn't vary outside the xsl:choose:
<xsl:for-each select="xhtml:p">
<xsl:variable...>
<DIV DEPTH="1">
<HEADER>
<xsl:choose>
<xsl:when test="contains($textcontent,'OBJECTIVE')"
>OBJECTIVE</xsl:when>
<xsl:when test="contains($textcontent,'BACKGROUND')"
>BACGROUND</xsl:when>
....
</DIV>
Beyond that, you can call a named template with parameters but it wouldn't reduce the number of lines of code very much.
Your logic can probably be simplified if one knows more about the source document, for example can a p element contain more than one of these strings, and is the order of testing them important? The following 2.0 code isn't equivalent to yours, but might give the right result depending on the data:
<xsl:for-each select="xhtml:p">
<xsl:variable name="textcontent" select="text()"/>
<DIV DEPTH="1">
<HEADER>
<xsl:for-each select="'OBJECTIVE', 'BACKGROUND', 'METHODS'...">
<xsl:if test="contains($textcontent, .)">
<xsl:value-of select="."/>
....
</DIV>
Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference