Strip HTML-like characters (not markup) from XML with XSLT? - xslt

Is there a way to strip all HTML from XML with XSLT,
like PHP strip_tags() ?
I want to keep the text, but remove all formatting, etc.
This will be taking place before truncating.
Hey Kurt, <br> I'd like to suggest that we start inventorying a system feature list at a <br> high-level. From there, we would define the requirements of the features. <br> Next, design to the requirements, develop, test, deploy..wash, rinse, and <br> repeat.. <br> I.E. <br> Event Calendar <br> - Requirement No. 1 <br> - Requirement No. 2

I found this solution on various places in the internet using Google:
Some examples of my research:
here, here, here
<!-- Calling the template that removes tag -->
<xsl:call-template name="remove-html">
<xsl:with-param name="text" select="{HtmlBody}"/>
</xsl:call-template>
<!-- This will remove the tag -->
<xsl:template name="remove-html">
<xsl:param name="text"/>
<xsl:choose>
<xsl:when test="contains($text, '<')">
<xsl:value-of select="substring-before($text, '<')"/>
<xsl:call-template name="remove-html">
<xsl:with-param name="text" select="substring-after($text, '>')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

Related

How do you get DocBook XSL's chunking to generate a full TOC for each page?

I have a bunch of DocBook XML files that all get merged into a single DocBook file for conversion into HTML. Each individual document is a reference page (for a function or similar construct). I use chunked HTML generation, so that each reference page becomes its own HTML page.
The problem is this: I want a table of contents on each page. But I don't want the table of contents for that page. I want the full TOC for the entire reference manual.
That is, from any page, I want to be able to jump to any other page by using the TOC. I can use CSS styling to stick the TOC on the left side (and even hide it for mobile viewing or whatever).
There's an obvious way to handle this. I could extract the main TOC via a post-process script and have the script copy this into each of the output HTML documents. What I'm looking for is a way to do it that works within DocBook XSL.
I want the results to look rather like DocBook XSL's newer webhelp, but with less overt JavaScript involvement.
As of 2019-07-06 with docbook-xsl-1.79.2 the currently accepted answer isn't sufficient to make each table of contents complete.
The following XSL template does, however. The key insight was stepping through with the Oxygen XML editor's debugger and noticing that while the toc-context was correctly set to the root element, the nodes variable was still the local subset.
I undid the toc-context change. Instead I created a new variable root-nodes selecting /, and edited the make.toc template to use root-nodes instead of nodes.
Putting this in my customisation layer now makes every table of contents a complete table of contents.
<xsl:template name="make.toc">
<xsl:param name="toc-context" select="."/>
<xsl:param name="toc.title.p" select="true()"/>
<xsl:param name="nodes" select="/NOT-AN-ELEMENT"/>
<xsl:variable name="root-nodes" select="/"/>
<xsl:variable name="nodes.plus" select="$root-nodes | d:qandaset"/>
<xsl:variable name="toc.title">
<xsl:if test="$toc.title.p">
<xsl:choose>
<xsl:when test="$make.clean.html != 0">
<div class="toc-title">
<xsl:call-template name="gentext">
<xsl:with-param name="key">TableofContents</xsl:with-param>
</xsl:call-template>
</div>
</xsl:when>
<xsl:otherwise>
<p>
<strong>
<xsl:call-template name="gentext">
<xsl:with-param name="key">TableofContents</xsl:with-param>
</xsl:call-template>
</strong>
</p>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:variable>
<xsl:choose>
<xsl:when test="$manual.toc != ''">
<xsl:variable name="id">
<xsl:call-template name="object.id"/>
</xsl:variable>
<xsl:variable name="toc" select="document($manual.toc, .)"/>
<xsl:variable name="tocentry" select="$toc//d:tocentry[#linkend=$id]"/>
<xsl:if test="$tocentry and $tocentry/*">
<div class="toc">
<xsl:copy-of select="$toc.title"/>
<xsl:element name="{$toc.list.type}" namespace="http://www.w3.org/1999/xhtml">
<xsl:call-template name="toc.list.attributes">
<xsl:with-param name="toc-context" select="$toc-context"/>
<xsl:with-param name="toc.title.p" select="$toc.title.p"/>
<xsl:with-param name="nodes" select="$root-nodes"/>
</xsl:call-template>
<xsl:call-template name="manual-toc">
<xsl:with-param name="tocentry" select="$tocentry/*[1]"/>
</xsl:call-template>
</xsl:element>
</div>
</xsl:if>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="$qanda.in.toc != 0">
<xsl:if test="$nodes.plus">
<div class="toc">
<xsl:copy-of select="$toc.title"/>
<xsl:element name="{$toc.list.type}" namespace="http://www.w3.org/1999/xhtml">
<xsl:call-template name="toc.list.attributes">
<xsl:with-param name="toc-context" select="$toc-context"/>
<xsl:with-param name="toc.title.p" select="$toc.title.p"/>
<xsl:with-param name="nodes" select="$root-nodes"/>
</xsl:call-template>
<xsl:apply-templates select="$nodes.plus" mode="toc">
<xsl:with-param name="toc-context" select="$toc-context"/>
</xsl:apply-templates>
</xsl:element>
</div>
</xsl:if>
</xsl:when>
<xsl:otherwise>
<xsl:if test="$root-nodes">
<div class="toc">
<xsl:copy-of select="$toc.title"/>
<xsl:element name="{$toc.list.type}" namespace="http://www.w3.org/1999/xhtml">
<xsl:call-template name="toc.list.attributes">
<xsl:with-param name="toc-context" select="$toc-context"/>
<xsl:with-param name="toc.title.p" select="$toc.title.p"/>
<xsl:with-param name="nodes" select="$root-nodes"/>
</xsl:call-template>
<xsl:apply-templates select="$root-nodes" mode="toc">
<xsl:with-param name="toc-context" select="$toc-context"/>
</xsl:apply-templates>
</xsl:element>
</div>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Note: there is a remaining issue where not every chunked page gets its own ToC, but that is unrelated to this specific. If I sort it, I'll add a comment on how I did that.
There’s a relatively easy way to get that, though I’m pretty sure you can’t without either creating a DocBook XSL customization layer or just directly modifying the installed (system) stylesheets.
Either way, I think the actual docbook-xsl template you need to modify or override is named make.toc, located in the stylesheets distribution in the file html/autotoc.xsl.
It’s a big template—nearly a hundred lines—but you only need to make a one-line change to it:
--- /usr/share/xml/docbook/stylesheet/docbook-xsl/html/autotoc.xsl 2012-12-16 11:35:12.000000000 +0900
+++ /opt/workspace/autotoc.xsl 2015-12-26 09:19:36.000000000 +0900
## -28,7 +28,7 ##
</xsl:variable>
<xsl:template name="make.toc">
- <xsl:param name="toc-context" select="."/>
+ <xsl:param name="toc-context" select="/"/>
<xsl:param name="toc.title.p" select="true()"/>
<xsl:param name="nodes" select="/NOT-AN-ELEMENT"/>
That is, you need to call that template with the toc-context param set to "/" (instead of ".").
The default "." value tells the template that, when creating a TOC for a chunk, it should only look at the (child) content of whatever element it’s currently processing (that is, the root of that particular chunk); for example, if it’s processing a section it looks only at the children of that section.
But if you instead change that value to "/", you’re telling the template to (re)look at the entire content of the source document each time. So if your document is a book, it’ll give you the entire TOC for the whole book each time, or if your document is an article, the entire article, etc.
So I think that should give you what you’re wanting.
If you decide to just modify the installed stylesheets and you’ve installed them from any OS-specific package manager you use, you need to find where the html/autotoc.xsl file is installed.
On my Debian Linux system the html/autotoc.xsl file is here:
/usr/share/xml/docbook/stylesheet/docbook-xsl/html/autotoc.xsl
And on my OS X system, installed from a homebrew package, it’s here:
/usr/local/opt/docbook-xsl/docbook-xsl/html/autotoc.xsl
If you decide to instead create a customization layer, you’ll need to copy that entire make.toc template into your customization layer (but with that toc-context param changed to "/").

How to show custom metadata in DSpace's summary view?

I just "inherited" this repository in my office. I have no experience at all with it and I've been asked to show custom metadata below an item's title in the summary view. The custom metadata has already been registered (it is called dc.magazine.title) and I managed to edit the input forms so that all the new metadata can be registered in the database.
The repository is using the default mirage theme with XMLUI. I have changed some code in the file DIM-Handler.xsl trying to emulate how the other info is rendered but I have no idea how it works so my approach has given no results. This is what I tried:
<!-- Magazine row -->
<tr class="ds-table-row {$phase}">
<td><span class="bold"><i18n:text>xmlui.dri2xhtml.METS-1.0.item-title</i18n:text>: </span></td>
<td>
<xsl:choose>
<xsl:when test="count(dim:field[#element='magazine'][#qualifier='title']) = 1">
<xsl:value-of select="dim:field[#element='magazine'][#qualifier='title'][1]/node()"/>
</xsl:when>
<xsl:otherwise>
<i18n:text>xmlui.dri2xhtml.METS-1.0.no-title</i18n:text>
</xsl:otherwise>
</xsl:choose>
</td>
</tr>
<xsl:call-template name="itemSummaryView-DIM-fields">
<xsl:with-param name="clause" select="($clause + 1)"/>
<xsl:with-param name="phase" select="$otherPhase"/>
</xsl:call-template>
But nothing is showing besides the default metadata. Can somebody give me a hand on how to show this new metadata? Some clues on how this code works so I can make future changes will be really appreciated!
If you are using the default installation of DSpace using the Mirage 1 theme, the display of the item's metadata is rendered in [DSpace-installed-directory]/webapps/xmlui/themes/Mirage/lib/xsl/aspect/artifac‌​tbrowser/item-view.xsl. In my comment, I specified [DSpace-installed-directory] since I'm not so sure if the repository you 'inherited' could be using a customized theme with a different theme name other than Mirage.
You said that you are required to show a custom metadata below the item's title. Try to insert this before the <!-- Author(s) row -->
<xsl:when test="$clause = 2 and (dim:field[#element='magazine' and #qualifier='title' and descendant::text()])">
<div class="simple-item-view-other">
<span class="bold"><i18n:text>xmlui.dri2xhtml.METS-1.0.item-title</i18n:text>:</span>
<span>
<xsl:for-each select="dim:field[#element='magazine' and #qualifier='title']">
<xsl:value-of select="./node()"/>
<xsl:if test="count(following-sibling::dim:field[#element='magazine' and #qualifier='title']) != 0">
<br/>
</xsl:if>
</xsl:for-each>
</span>
</div>
<xsl:call-template name="itemSummaryView-DIM-fields">
<xsl:with-param name="clause" select="($clause + 1)"/>
<xsl:with-param name="phase" select="$otherPhase"/>
</xsl:call-template>
</xsl:when>
Please take note of the $clause number. You should update all the clause number below ie the author's row should be $clause = 3 down to the part of
<!-- IMPORTANT: This test should be updated if clauses are added! -->
<xsl:if test="$clause < 8">
<xsl:call-template name="itemSummaryView-DIM-fields">
<xsl:with-param name="clause" select="($clause + 1)"/>
<xsl:with-param name="phase" select="$phase"/>
</xsl:call-template>
</xsl:if>
#euler Thank you for your answer, with your post, (though 4 years old), I was able to make out how this simple item view works and created an entry with dc.identifier.citation. as follows
<xsl:when test="$clause = 6 and (dim:field[#element='identifier' and #qualifier='citation'])">
<div class="simple-item-view-other">
<span class="bold"><i18n:text>xmlui.ETCRiverRun.METS-1.0.item-citation</i18n:text>:</span>
<span>
<xsl:for-each select="dim:field[#element='identifier' and #qualifier='citation']">
<xsl:copy-of select="./node()"/>
<xsl:if test="count(following-sibling::dim:field[#element='identifier' and #qualifier='citation']) != 0">
<br/>
</xsl:if>````

confusing error thown while trying to match templates

I've the below XML line of code.
<entry colname="col3" align="left" valign="top"><para>grandchild, cousin, <content-style font-style="italic">etc</content-style>., shall be described as “lawful” and “one of the next-of-kin” or “only next-of-kin”.</para></entry>
and below XSL
<xsl:template match="entry" name="entry">
<xsl:choose>
<xsl:when test="./#namest">
<xsl:variable name="namest" select="#namest" />
<xsl:variable name="nameend" select="#nameend" />
<xsl:variable name="namestPos" select="count(ancestor::tgroup/colspec[#colname=$namest]/preceding-sibling::colspec)" />
<xsl:variable name="nameendPos" select="count(ancestor::tgroup/colspec[#colname=$nameend]/preceding-sibling::colspec)" />
<td colspan="{$nameendPos - $namestPos + 1}" align="{#align}">
<xsl:apply-templates select="child::node()[not(self::page)]" />
</td>
</xsl:when>
<xsl:otherwise>
<td>
<xsl:if test="./#morerows">
<xsl:attribute name="rowspan">
<xsl:value-of select="number(./#morerows)+1" />
</xsl:attribute>
</xsl:if>
<xsl:if test="./#align">
<xsl:attribute name="align">
<xsl:value-of select="#align" />
</xsl:attribute>
</xsl:if>
<xsl:if test="./#valign">
<xsl:attribute name="valign">
<xsl:value-of select="#valign" />
</xsl:attribute>
</xsl:if>
<xsl:for-each select="para">
<div class="para">
<xsl:choose>
<xsl:when test="../#colname='col3' and contains(./text(),'.')">
<xsl:variable name="strl">
<xsl:value-of select="fn:string-length(fn:substring-before(.,'.'))" />
</xsl:variable>
<xsl:choose>
<xsl:when test="$strl < '6'">
<a href="{concat('er:#SCP_ORD_',//chapter/#num,'/','P',translate(./text(),'.','-'))}">
<xsl:value-of select="./text()" />
</a>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates />
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates />
</xsl:otherwise>
</xsl:choose>
</div>
</xsl:for-each>
</td>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
and when i run this on my XML in the above mentioned line(the XML given in the sample), it is throwing me an error. and the error is as below.
Wrong occurrence to match required sequence type - Details: - XPTY0004: The supplied sequence ('2' item(s)) has the wrong occurrence to match the sequence type xs:string ('zero or one')
here what i actually was trying to achieve is, i have another table(which is basically a TOC), where in there is some linking needed, and below is such sample entries.
<entry colname="col3" align="right" valign="top"><para>A.1</para></entry>
<entry colname="col3" align="right" valign="top"><para>A.2</para></entry>
here i'm searching if the colname is col3 and if this has a . in it, and the above two cases mentioned are passing and are getting linked successfully, where in the case mentioned in the top is throwing the error, can anyone please suggest some better method to differentiate these two cases, and i use XSLT 2.0.
Thanks
The problem is
contains(./text(),'.')
./text() is not "the text of the current element" but rather the sequence of all text node children of the current element. In the case of
<para>grandchild, cousin, <content-style font-style="italic">etc</content-style>., shall be described as “lawful” and “one of the next-of-kin” or “only next-of-kin”.</para>
there are two such nodes, one containing everything between the <para> and <content-style> tags ("grandchild, cousin, " including the trailing space) and the other containing everything between the </content-style> and the </para>. But the contains function expects its first argument to be a single string, not a sequence of two nodes.
Instead of testing ./text() you probably just need to test .:
contains(., '.')
which is interpreted as the string value of the whole para element, i.e. a single string consisting of the concatenation of all the descendant text nodes (so the whole text "grandchild, cousin, etc., shall be described...").

XSL counter on specific condition for SharePoint 2010 CQWP

This is the first time I have ever posted a question so apologese in advance if I jibber here.
I am trying to put together a CQWP with jQuery tabs slider functionality. The HTML I want to output should be in the form of 2 UL's. The first with li anchor tags with #associated-ul-id
The second ul's should have ids that associate with the list items in the first. Eg
<div id="tabs" class="news">
<div class="news-pagination">
« Prev
<ul id="carouseltext" class="horizontal-text order">
<li>System</li>
<li>School</li>
</ul>
» Next
<div class="clear"> </div>
</div>
<ul id="tabs-1" class="feed order">
<li>title 1</li>
<li>title 2</li>
</ul>
<ul id="tabs-2" class="feed order">
<li>title 3</li>
</ul>
</div>
The original XML starts off in the form
My XSL goes through the XML twice to fill the 2 ul's. The first time it just adds a new list item when the __begincolumn and __begingroup variables are true. I striped down the functionality here to just output the header. Here's a stripped down version of the XSL
<xsl:template match="/">
<xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row" />
<xsl:variable name="RowCount" select="count($Rows)" />
<xsl:variable name="FirstRow" select="1" />
<xsl:param name="ColNumber" select="1" />
<xsl:for-each select="$Rows" >
<xsl:variable name="CurPosition" select="position()" />
<xsl:variable name="BeginNewsItemsList1" select="string('<ul id="tabs-')" />
<xsl:variable name="BeginNewsItemsList2" select="string('"class="feed order">')" />
<xsl:variable name="BeginNewsItemsList" select="concat($BeginNewsItemsList1, $ColNumber, $BeginNewsItemsList2)" />
<xsl:if test="($CurPosition >= $FirstRow and $CurPosition <= $LastRow)">
<xsl:variable name="StartNewGroup" select="#__begingroup = 'True'" />
<xsl:variable name="StartNewColumn" select="#__begincolumn = 'True'" />
<xsl:when test="$StartNewGroup and $StartNewColumn">
<xsl:choose>
<xsl:when test="$CurPosition = $FirstRow">
<xsl:value-of disable-output-escaping="yes" select="$BeginNewsItemsList" />
</xsl:when>
<xsl:otherwise>
<!-- other instructions -->
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$StartNewGroup">
<xsl:call-template name="OuterTemplate.CallFooterTemplate"/>
<xsl:value-of disable-output-escaping="yes" select="concat($EndColumn, $BeginNewsItemsList)" />
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template name="OuterTemplate.Count">
<xsl:param name="ColNumber" />
<xsl:value-of select="$ColNumber + 1" />
</xsl:template>
For the second for-each loop I'm having trouble setting up a counter so that I can add the number to the end of the id for each new list id="tabs-1", id="tabs-2", etc.
In theory I think I should set a parameter outside my for-each loop and then in the loop call a template that gets the parameter value and increments it. That would mean it would increment only when the template is called.
I can't use position() for this as it doesn't correspond to the values I want. I've tried to follow a couple a few blogs about recursive programming with xsl, but I can't seem to find anything that works. I'm sure I'm just writing the XSL wrong, but I'm having a bit of a brain dump now.
If anybody could point me in the right direction that would be awesome. Thanks very much.
You can't change variable's values after declaration. You can use them in expressions and/or pass as parameters. Thus, you can't use outside variable as counter explicitly. One available trick is recursive cycle like:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="root">
<HTML>
<BODY>
<xsl:call-template name="for">
<xsl:with-param name="i" select="1"/>
<xsl:with-param name="n" select="5"/>
</xsl:call-template>
</BODY>
</HTML>
</xsl:template>
<xsl:template name="for">
<xsl:param name="i"/>
<xsl:param name="n"/>
<xsl:value-of select="$i"/>
<xsl:if test="$i < $n">
<xsl:text>, </xsl:text>
<xsl:call-template name="for">
<xsl:with-param name="i" select="$i+1"/>
<xsl:with-param name="n" select="$n"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
result:
1, 2, 3, 4, 5

Using Multiple Nested Attributes in XSLT

What is the best way to construct nested attributes in XSL?
My issue is that onmouseover is an attribute and the src of img is an attribute. The current error given by the builder is:
An item of type 'Element' cannot be constructed within a node of type 'Attribute'.
I used to have an issue of multiple attributes which would have been my preferred route but throws an error:
Attribute and namespace nodes cannot be added to the parent element after a text, comment, pi, or sub-element node has already been added.
I have since attempted the following as a workaround but with no luck
<xsl:template name="Item3">
<xsl:param name="ItemID" />
<xsl:variable name="IMGSRC">
<xsl:choose>
<xsl:when test="$ItemID = 'ST-18/NM/NM/36'">
<xsl:value-of select="concat('imagesCategories/','ST-18-NM-NM-36','.jpg')"/>
</xsl:when>
<xsl:when test="$ItemID = 'ST-18/NM/NM/48'">
<xsl:value-of select="concat('imagesCategories/','ST-18-NM-NM-48','.jpg')"/>
</xsl:when>
<xsl:when test="$ItemID = 'ST-18/NM/NM/72'">
<xsl:value-of select="concat('imagesCategories/','ST-18-NM-NM-72','.jpg')"/>
</xsl:when>
<xsl:when test="$ItemID = 'ST-18/SMAM/SMAM/12'">
<xsl:value-of select="concat('imagesCategories/','ST18-SMAM-SMAM-12','.jpg')"/>
</xsl:when>
<xsl:when test="$ItemID = 'ST-18/SMAM/SMAM/24'">
<xsl:value-of select="concat('imagesCategories/','ST18-SMAM-SMAM-24','.jpg')"/>
</xsl:when>
<xsl:when test="$ItemID = 'ST-18/SMAM/SMAM/36'">
<xsl:value-of select="concat('imagesCategories/','ST18-SMAM-SMAM-36','.jpg')"/>
</xsl:when>
<xsl:when test="$ItemID = 'ST-18/SMAM/SMAM/48'">
<xsl:value-of select="concat('imagesCategories/','ST18-SMAM-SMAM-48','.jpg')"/>
</xsl:when>
<xsl:when test="$ItemID = 'ST-18/SMAM/SMAM/60'">
<xsl:value-of select="concat('imagesCategories/','ST18-SMAM-SMAM-60','.jpg')"/>
</xsl:when>
<xsl:when test="$ItemID = 'ST-18/SMAM/SMAM/72'">
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat('imagesCategories/',$ItemID,'.jpg')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:choose>
<xsl:when test="Items/Item[#ItemID=$ItemID]">
<xsl:attribute name="onmouseover">
<xsl:text>ddrivetip('</xsl:text>
<img src="{$IMGSRC}"/>
<br />
<b>
<xsl:value-of select="Items/Item[#ItemID=$ItemID]/#ItemID" />
</b>
<br />
<b>
<xsl:value-of select="Items/Item[#ItemID=$ItemID]/#ItemDescription" />
</b>
<br />
<br />
<xsl:text>Price (01-09): </xsl:text>
<xsl:value-of select="Items/Item[#ItemID=$ItemID]/#PriceLevel1" />
<br/>
<xsl:text>Price (10-24): </xsl:text>
<xsl:value-of select="Items/Item[#ItemID=$ItemID]/#PriceLevel2" />
<br/>
<xsl:text>Price (25-49): </xsl:text>
<xsl:value-of select="Items/Item[#ItemID=$ItemID]/#PriceLevel3" />
<br/>
<xsl:text>Qty In Stock: </xsl:text>
<xsl:value-of select="Items/Item[#ItemID=$ItemID]/#QtyOnHand" />
<br />
<br />
<xsl:text>Click </xsl:text>
<b>
<xsl:text>"BUY!"</xsl:text>
</b>
<xsl:text> to add this item to your shopping cart</xsl:text>
<xsl:text>', '', '300')</xsl:text>
</xsl:attribute>
There is some additional code and then the proper closing tags.
Thanks everyone!
It looks like you are trying to pass html as a string to your ddrivetip function. However, you are adding these as nodes instead of text, and nodes cannot be added added to attributes, so one solution is to make the nodes text (You'll have to escape the brackets and double quotes too).
However, you are putting a lot of information into the onmouseover event, which is not recommended. Instead of what you are currently doing, I would make a hidden element with an id that incorporates your itemId with the contents of your html and then show that as needed in your onmouseover event.
Use CDATA sections so that the XSLT Processor interpret your img tags as a part of text nodes and not as an attempt to insert element nodes into an attribute (it is forbidden by the XML specification)
<xsl:attribute name="onmouseover">
<xsl:text><![CDATA[ddrivetip('<img src="]]></xsl:text>
<xsl:value-of select="$IMGSRC" />
<xsl:text><![CDATA["/>
<br />
...