I'm trying to edit the link within the CDATA:
<paragraph>
<![CDATA[
<strong><a href="http://example.com/2014/12/08/article-title">Article Title</a></strong>Article Excerpt.
]]>
</paragraph>
The goal is to change paragraph to <p> and at the same time, add additional tags inside the link. For example, the desired output can be: (not all the <paragraph> have links in it, some contains only text)
<p>
<strong><a href="http://example.com/2014/12/08/article-title?tacking_id=12345" style="font-size:1.1em; color:#067ab4; line-height:100%">Article Title</a></strong>Article Excerpt.
</p>
I have tried the following code but it didn't work.
<xsl:template match="paragraph">
<xsl:copy-of select="@*"/>
<xsl:text disable-output-escaping="yes"><![CDATA[<p>]]></xsl:text>
<xsl:value-of select="." disable-output-escaping="yes"/>
<xsl:text disable-output-escaping="yes"><![CDATA[</p>]]></xsl:text>
</xsl:template>
<xsl:template match="text()[contains(.,'<a href="') and contains(.,'">')]">
<xsl:variable name="link" select="substring-before(substring-after(., '<a href="'), '">')"/>
<xsl:text disable-output-escaping="yes"><![CDATA[<a href="]]></xsl:text>
<xsl:value-of disable-output-escaping="yes" select="$link"/>
<xsl:text disable-output-escaping="yes"><![CDATA[&tracking_id=12345" ]]></xsl:text>
<xsl:value-of select="$link_style"/>
<xsl:text disable-output-escaping="yes"><![CDATA[>]]></xsl:text>
<xsl:apply-templates select="child::node()"/>
<xsl:text disable-output-escaping="yes"><![CDATA[</a>]]></xsl:text>
</xsl:template>
As far as the XML processor is concerned, the CDATA in the paragraph node does not contain links, or tags, or anything other than a single text node. It is just a string of characters, so you have to resort to some tricksy string manipulation if you really wanted to change it.
The first problem you have is that in the template matching "paragraph", you don't do any xsl:apply-templates, so your second template that could match the text node under paragraph is never called.
You first template should therefore look like this
<xsl:template match="paragraph">
<p>
<xsl:apply-templates />
</p>
</xsl:template>
Now, in the template matching the text node, this is where it gets nasty, but your main problem is that you do <xsl:apply-templates select="child::node()"/>. But it is a text node. A single text node. It has no child nodes on which you can match.
If you really, really wanted to get it to work this way, the template would look like this
<xsl:template match="text()[contains(.,'<a href="') and contains(.,'">')]">
<xsl:variable name="firstbit" select="substring-before(., '<a href="')"/>
<xsl:variable name="link" select="substring-before(substring-after(., '<a href="'), '">')"/>
<xsl:variable name="lastbit" select="substring-after(substring-after(., '<a href="'), '">')"/>
<xsl:value-of disable-output-escaping="yes" select="$firstbit"/>
<xsl:text disable-output-escaping="yes"><![CDATA[<a href="]]></xsl:text>
<xsl:value-of disable-output-escaping="yes" select="$link"/>
<xsl:text disable-output-escaping="yes"><![CDATA[?tracking_id=12345" ]]></xsl:text>
<xsl:value-of select="$link_style"/>
<xsl:text disable-output-escaping="yes"><![CDATA[>]]></xsl:text>
<xsl:value-of disable-output-escaping="yes" select="$lastbit"/>
</xsl:template>
This answer probably demonstrates why trying to manipulate CDATA is a bad idea.
Another less unpleasant way would be to do TWO XSLT transforms.
The first one would just look like this
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="paragraph">
<p>
<xsl:value-of disable-output-escaping="yes" select="." />
</p>
</xsl:template>
</xsl:stylesheet>
This would output the following:
<p>
<strong><a href="http://example.com/2014/12/08/article-title">Article Title</a></strong>Article Excerpt.
</p>
It then becomes trivial to do the required transform the a tags in this then....
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="a">
<a href="{@href}?tracking_id=12345" style="color:#067ab4;">
<xsl:apply-templates />
</a>
</xsl:template>
</xsl:stylesheet>
This then outputs the following:
<p>
<strong><a href="http://example.com/2014/12/08/article-title?tracking_id=12345" style="color:#067ab4;">Article Title</a></strong>Article Excerpt.
</p>
So, if you can change your input XML to eliminate the CDATA, then it becomes a whole lot easier.....
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With