Replace HTML Quotes with Plain Text in XSLT - html

We are using XSLT to translate a RIXML file to XML. Our RIXML contains the following text:
<Title><![CDATA[Looking into the future: Reiterate ‘Buy’]]></Title>
8216 is a left quote and 8217 is a right quote.
How would I replace these HTML codes with their plain text representation, or more simply, just a single quote? This is XSLT version 1.0.

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="vQ2">""</xsl:variable>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()">
<xsl:value-of select=
"translate(.,'‘’',$vQ2)"/>
</xsl:template>
</xsl:stylesheet>

I came upon this function which worked well for me. I call it to replace all the characters I need to:
<xsl:template name="string-replace-all">
<xsl:param name="text" />
<xsl:param name="replace" />
<xsl:param name="by" />
<xsl:choose>
<xsl:when test="contains($text, $replace)">
<xsl:value-of select="substring-before($text,$replace)" />
<xsl:value-of select="$by" />
<xsl:call-template name="string-replace-all">
<xsl:with-param name="text"
select="substring-after($text,$replace)" />
<xsl:with-param name="replace" select="$replace" />
<xsl:with-param name="by" select="$by" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>

Related

XSLT template to replace string with string Including HTML Tags

I have this template to replace once string with another:
<xsl:template name="X">
<xsl:param name="field"/>
<xsl:param name="target"/>
<xsl:param name="change"/>
<xsl:value-of select='replace($field, $target, $change )' />
</xsl:template>
This is how I am calling it:
<xsl:call-template name="X">
<xsl:with-param name="field" select="artist"/>
<xsl:with-param name="target" select="'\\n'"/>
<xsl:with-param name="change" select="'
'"/>
</xsl:call-template>
This works in most cases except for the case demonstrated here.
I am trying to replace the string "\n" with a HTML line break <br> or <br />.
I want an actual new line not the tag visible in the output.
I know that it is matching on the \n but I can not make the line break happen.
I either get a literal <br> in the output or nothing happens.
You will need to change your approach. Your template is using replace() which works with strings. You want to replace with markup. I'd use xsl:analyze-string instead:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="break"><br/></xsl:variable>
<xsl:call-template name="X">
<xsl:with-param name="field" select="artist"/>
<xsl:with-param name="target" select="'\n'"/>
<xsl:with-param name="change" select="$break"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="X">
<xsl:param name="field"/>
<xsl:param name="target"/>
<xsl:param name="change"/>
<!-- <xsl:value-of select='replace($field, $target, $change )' />-->
<xsl:analyze-string select="$field" regex="{$target}">
<xsl:matching-substring>
<xsl:sequence select="$change"/>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
</xsl:stylesheet>

XSLT - How to add new tag each X characters

I want to add a new tag <br\> to my XML each 10 characters. (without including inner nodes)
For example if my input is:
<main>
01234567890123
<a>
link
</a>
45678901234567901234
</main>
I expect is to be somthing like:
<main>
0123456789<br\>0123
<a>
link
</a>
456789<br\>012345679<br\>01234
</main>
I wrote this function:
<!-- Add new "HTML Break" Every X chars -->
<xsl:template name="Add-HTML-Break-After-X-Chars">
<xsl:param name="text" />
<xsl:param name="max-length" />
<xsl:choose>
<xsl:when test="string-length($text) > $max-length">
<!-- Show the X length of the text -->
<xsl:copy-of select="substring($text,1,$max-length)" />
<!-- Adding the special tag -->
<br/>
<!-- continue to add the rest of the text -->
<xsl:call-template name="Add-HTML-Break-After-X-Chars">
<xsl:with-param name="text" select="substring($text, $max-length + 1)" />
<xsl:with-param name="max-length" select="$max-length" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<!-- Show the text (length is less then X) -->
<xsl:copy-of select="$text" />
</xsl:otherwise>
</xsl:choose>
The problem is that I'm getting the output without the inner tags:
<main>
0123456789<br\>0123
link
45<br\>6789012345<br\>67901234
</main>
I'm using this code to call the template:
<xsl:call-template name="Add-HTML-Break-After-X-Chars">
<xsl:with-param name="text" select="main" />
<xsl:with-param name="max-length" select="10" />
</xsl:call-template>
I tried also "value-of" instead of "copy-of".
Is there a way I can keep the tags?
If so, how can I keep them and make a "safe" insert of the new tag?
This is difficult to do in XSLT, because it processes each text node individually, with no information being carried over from the preceding text nodes.
Here's a possible approach:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="main/text()" name="wrap">
<xsl:param name="text" select="."/>
<xsl:param name="line-length" select="10"/>
<xsl:param name="carry">
<xsl:variable name="lengths">
<xsl:for-each select="preceding-sibling::text()">
<length>
<xsl:value-of select="string-length()"/>
</length>
</xsl:for-each>
</xsl:variable>
<xsl:value-of select="sum(exsl:node-set($lengths)/length) mod $line-length"/>
</xsl:param>
<xsl:value-of select="substring($text, 1, $line-length - $carry)"/>
<br/>
<xsl:if test="$carry + string-length($text) > $line-length">
<!-- recursive call -->
<xsl:call-template name="wrap">
<xsl:with-param name="text" select="substring($text, $line-length - $carry + 1)"/>
<xsl:with-param name="carry" select="0"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
When this is applied to the following test input:
XML
<main>A123456789B123<a>link1</a>456789C123456789D12345678<a>link2</a>9E123456789F1234567</main>
the result will be:
<?xml version="1.0" encoding="UTF-8"?>
<main>A123456789<br/>B123<a>link1</a>456789<br/>C123456789<br/>D12345678<a>link2</a>9<br/>E123456789<br/>F1234567</main>

xslt 1.0 - translate stirng backslash to double backslash

My xml:
<workorder>
<specifications>
<hpath>94 \ 72</hpath>
<classdesc></classdesc>
</specifications>
</workorder>
my xslt:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0">
<xsl:output method="text" encoding="UTF-8" />
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="workorder">
<xsl:apply-templates select="specifications" />
</xsl:template>
<xsl:template match="specifications">
<xsl:text>{
"Hierarchy Path"="</xsl:text>
<xsl:value-of select="translate(//workorder/specifications/hpath,'\','\\')" />
<xsl:text>"
}</xsl:text>
</xsl:template>
</xsl:stylesheet>
Expecting output is:
{
"Hierarchy Path"="94 \\ 72"
}
Current output is :
{
"Hierarchy Path"="94 \ 72"
}
Problem is: When I send json format as "Current output", not a valid json format.
If I send as "Expected output", it is a valid json format.
Please help. Thanks in advance.
With XSLT 1.0 you need a recursive approach.
You may try something like this named template.
<xsl:template name="jsonescape">
<xsl:param name="str" select="."/>
<xsl:choose>
<xsl:when test="contains($str, '\')">
<xsl:value-of select="concat(substring-before($str, '\'), '\\' )"/>
<xsl:call-template name="jsonescape">
<xsl:with-param name="str" select="substring-after($str, '\')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$str"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
And call it with your strings(for example).
<xsl:call-template name="jsonescape">
<xsl:with-param name="str" select="//workorder/specifications/hpath"/>
</xsl:call-template>

XSL Delimited Values for HTML Links and their Descriptions

I am trying to debug some xsl code that puts links gathered from an XML Document with their descriptions in a list, it seems to be working, except when handling multiple links gathered from a single string that are delimited with a "|" and "^" symbol.
The XML Line that contains this code is very similar to this:
<WebContent>
<content_type_desc>Links</content_type_desc>
<content_value>Google|http://www.google.com^Yahoo|http://www.yahoo.com^Bing|Http://www.bing.com</content_value>
</WebContent>
The xsl that handles this is like
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"xmlns="http://www.w3.org/1999/xhtml">
<xsl:output method="html" indent="yes" encoding="utf-8"/>
<xsl:template match="/">
<!--Links-->
<xsl:variable name="links" select="//WebContent[content_type_desc='Links']/content_value "/>
<!--Links-->
<!--Links section-->
<xsl:if test="$links != ''">
<br />
<xsl:choose>
<xsl:when test="contains($links,'^')">
<xsl:variable name="URL" select="substring-after(substring-before($links,'^'),'|')"/>
<xsl:variable name="URLText" select="substring-before($links,'|')"/>
<strong>Links: </strong><br />
<xsl:value-of select="$URLText"/>
<br />
</xsl:when>
<xsl:otherwise>
<xsl:variable name="URL" select="substring-after($links,'|')"/>
<xsl:variable name="URLText" select="substring-before($links,'|')"/>
<strong>Links: </strong><br />
<xsl:value-of select="$URLText"/>
<br />
</xsl:otherwise>
</xsl:choose>
<br />
</xsl:if>
<!--Links section-->
</xsl:template>
</xsl:stylesheet>
What's wrong with this is that it only outputs
<a href="http://www.google.com>Google</a>
When I would like it to output
<a href="http://www.google.com>Google</a>
<a href="http://www.yahoo.com>Yahoo</a>
<a href="http://www.bing.com>Bing</a>
Any help will be greatly appreciated as this has me completely stumped.
Assuming you are actually only using XSLT 1.0, to solve this you could make use of a named-template which is called recursively.
At the moment, the code is only processing the URL before the first ^ in the code. What you could do is put the main bulk of the code that checks the links variable in a named template. Then, in the xsl:when condition that runs when the URL does contain a ^ you add a recursive call to the named template, but passing in only the substring after the ^.
Try this XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"xmlns="http://www.w3.org/1999/xhtml">
<xsl:output method="html" indent="yes" encoding="utf-8"/>
<xsl:template match="/">
<xsl:param name="links" select="//WebContent[content_type_desc='Links']/content_value "/>
<xsl:if test="$links != ''">
<strong>Links: </strong>
<br />
<xsl:call-template name="splitlinks">
<xsl:with-param name="links" select="$links" />
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="splitlinks">
<xsl:param name="links" />
<xsl:choose>
<xsl:when test="contains($links,'^')">
<xsl:variable name="URL" select="substring-after(substring-before($links,'^'),'|')"/>
<xsl:variable name="URLText" select="substring-before($links,'|')"/>
<xsl:value-of select="$URLText"/>
<br />
<xsl:call-template name="splitlinks">
<xsl:with-param name="links" select="substring-after($links,'^')" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="URL" select="substring-after($links,'|')"/>
<xsl:variable name="URLText" select="substring-before($links,'|')"/>
<xsl:value-of select="$URLText"/>
<br />
</xsl:otherwise>
</xsl:choose>
<br />
</xsl:template>
</xsl:stylesheet>
Given that you have tagged your question as classic ASP your XSLT processor is likely some version of MSXML for which there is an implementation of http://www.exslt.org/str/functions/tokenize/index.html so you could use that.

How to sanitize Mysql queries with XSL template?

I have a XSL associate with an XML file. This XSL aim to create Mysql queries but in my XML I had some special characters like apostroph ' which break my queries. Do you know how I can sanitize my XSL template in order to have safe queries?
Example of my XML file
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="fnac.xsl"?>
<products xmlns="http://zanox.com/productdata/exportservice/v1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://zanox.com/productdata/exportservice/v1 http://productdata.zanox.com/exportservice/schema/export-1.1.xsd">
<product>
<name>jack o'connor</name>
<program>3467</program>
</product>
</products>
And my XSL file :
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:v1="http://zanox.com/productdata/exportservice/v1">
<xsl:output method="text" omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="//v1:product"/>
</xsl:template>
<xsl:template match="v1:product">
<xsl:text>insert into fnac (name, program) values(</xsl:text>
<xsl:value-of select="./v1:name"/>
<xsl:text>,'</xsl:text>
<xsl:value-of select="./v1:program"/>
<xsl:text>'); </xsl:text>
</xsl:template>
</xsl:stylesheet>
Thanks for your inputs!
If you want to remove apostrope from your XML file, you should use this xslt:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:v1="http://zanox.com/productdata/exportservice/v1">
<xsl:output method="text" omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="//v1:product"/>
</xsl:template>
<xsl:template match="v1:product">
<xsl:text>insert into fnac (name, program) values(</xsl:text>
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="./v1:name"/>
<xsl:with-param name="from">'</xsl:with-param>
<xsl:with-param name="to" select="' '"/>
</xsl:call-template>
<xsl:text>,'</xsl:text>
<xsl:value-of select="./v1:program"/>
<xsl:text>'); </xsl:text>
</xsl:template>
<xsl:template name="replace-string">
<xsl:param name="text"/>
<xsl:param name="from"/>
<xsl:param name="to"/>
<xsl:choose>
<xsl:when test="contains($text, $from)">
<xsl:variable name="before" select="substring-before($text, $from)"/>
<xsl:variable name="after" select="substring-after($text, $from)"/>
<xsl:copy-of select="$before"/>
<xsl:value-of select="$to" disable-output-escaping="yes"/>
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="$after"/>
<xsl:with-param name="from" select="$from"/>
<xsl:with-param name="to" select="$to"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
which would generate output:
insert into fnac (name, program) values(jack o connor,'3467');
If you only like/need to replace the apostrope , this could be done lot easier with translate().
Try this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:v1="http://zanox.com/productdata/exportservice/v1">
<xsl:output method="text" omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="//v1:product"/>
</xsl:template>
<xsl:template match="v1:product">
<xsl:text>insert into fnac (name, program) values(</xsl:text>
<xsl:value-of select='translate(./v1:name,"&apos;", " ")'/>
<xsl:text>,'</xsl:text>
<xsl:value-of select="./v1:program"/>
<xsl:text>'); </xsl:text>
</xsl:template>
</xsl:stylesheet>