The relevant parts of the code:
<xsl:variable name="apos">'</xsl:variable>
<xsl:variable name="and" select='"'"' />
<xsl:value-of select="translate(products_name/node(),$and,$apos)"/>
I'm thinking this should be a simple thing and that the above code should work but it doesn't effect the output at all.
(I used variables because names cannot begin within an ampersand and using just an apostrophe brings up a compile error.)
I've tested the code to make sure the translate is working using strings and there are no errors there.
Any help would be greatly appreciated.
You are on the right track, but not yet there: Your problem is, that XSL is a language that itself is written using XML. For all XML languages, the parser automatically decodes XML entities. The XSLT engine only comes afterwards.
As a result, the XSLT engine neither does nor can distinguish whether you wrote ' or ' - it's the same. For your problem, this has two effects:
You have to use a variable containing the apostrope - this is because the apostrophe itself is reserved for string literals in expressions that may contain functions. Even for <xsl:value-of select="translate(products_name/node(),$and,''')"/>, the XML parser transforms the entity into an apostrophe, i.e. <xsl:value-of select="translate(products_name/node(),$and,''')"/>
You have to escape the ampersand used in the string you search for: for the XSL engine, the variable "and" contains the value ', i.e. you are replacing an apostrophe with an apostrophe.
Working solution:
<xsl:variable name="apos">'</xsl:variable>
<xsl:value-of select='translate(text(), "'", $apos)'/>
Technically, there's no difference in any XML between ', ' and ', they're different ways of representing exactly the same thing. Therefore, that translate call shouldn't do anything.
It depends on how you're transforming it, where that output is (attribute value or element?), and how the output is serialized to text, but your problem isn't with your XSLT.
Related
Im using xslt for csv files. Sometimes there is a text like "a, b" in xml. When you choose comma delimited in excel for showing csv file, excel thinks that they have to separated to columns. But I want to do just for column. Is there a way to do that in xslt part?
In order to preserve spaces you need to quote values which contain commas. It is possible in XSLT, but the answer depends on your stylesheet design. If you want a more accurate answer, please share your code. Generally, you can use the following template to wrap any text nodes of interest in quotes:
<xsl:template match="text()[contains(., ', ')]">
<xsl:value-of select="concat('"', ., '"')"/>
</xsl:template>
You can get clues from the open-source CSV to XML package in XSLT 2.0 I've published in the "Free Developer" section of my web site: http://www.CraneSoftwrights.com/resources/#csv it follows RFC4180 http://www.ietf.org/rfc/rfc4180.txt
The idea is to look for quotes first and then commas when there aren't quotes. This can be expressed in regex as I have done in the code I've cited.
I'm converting DITA maps to PDF using the DITA Open Toolkit 1.7 and RenderX XEP. In the DITA topics, product names are inserted using conrefs. One of my product names is quite long. It caused layout problems when used within tables. Therefore I inserted a soft hyphen into the phrase that is reused via conref:
<ph id="PD_FineReader2Comp">DOXiS4 FineReader2Components</ph>
This works nicely in the generated pages, but creates a problem in the bookmarks where a symbol is displayed in place of the soft hyphen.
Obviously, this is an encoding problem. It seems that UTF-8 characters are properly handled in PDF content, but not in PDF bookmarks where, according to the following sources, some PDF-16 characters can be used (but I did not understand which ones).
http://partners.adobe.com/public/developer/en/pdf/PDFReference.pdf
http://www.setasign.de/support/tips-and-tricks/use-unicode-in-string-values/
The DITA Open Toolkit seems to create bookmarks from topic titles using this code fragment:
<fo:bookmark>
<xsl:attribute name="internal-destination">
<xsl:call-template name="generate-toc-id"/>
</xsl:attribute>
<xsl:if test="$bookmarkStyle!='EXPANDED'">
<xsl:attribute name="starting-state">hide</xsl:attribute>
</xsl:if>
<fo:bookmark-title>
<xsl:value-of select="normalize-space($topicTitle)"/>
</fo:bookmark-title>
<xsl:apply-templates mode="bookmark"/>
</fo:bookmark>
The XSL stylesheet has version 2.0.
I would like to create an override that removes the offending character. How can I do this?
Is it possible to properly resolve the encoding problem? (Probably not possible).
Are there any XSL functions or attributes which remove whitespace other than space, tab, linefeed, and carriage return?
Or do I need special handling for the soft hyphen?
Small refinement: If you are using XSLT2, will be more efficient than in this context. In XSLT2 you should always prefer xsl:sequence over xsl:value-of
The simple way to do this is to use the translate() function, which can be used to replace certain characters with other characters, or with nothing. It looks like this is the line that outputs the value you want to fix up:
<xsl:value-of select="normalize-space($topicTitle)"/>
So you could simply modify this to:
<xsl:value-of select="translate(normalize-space($topicTitle), '', '')"/>
to remove all the soft hyphens. If you would like to replace them with spaces or ordinary hyphens, you could do either of the following, respectively:
<xsl:value-of select="translate(normalize-space($topicTitle), '', ' ')"/>
<xsl:value-of select="translate(normalize-space($topicTitle), '', '-')"/>
I have a problem with text with apostrophe symbol
example i try to test this xml having the symbol is then how can i compare ?
<xsl:for each select="country[nation='India's]">
this is statement showing error
Regards
Nanda.A
One way to do it would be:
<xsl:variable name="apos" select='"'"'/>
<!-- ... later ... -->
<xsl:for-each select="country[nation=concat('India', $apos, 's')]">
The problem here is twofold:
XSLT defines no way of character escaping in strings. So 'India\'s' is not an option.
You must get through two distinct layers of evaluation.
These are:
XML well-formedness: The XML document your XSLT program consists of must be well-formed. You cannot violate XML rules.
XSLT expression parsing: The resulting attribute value string (after XML DOM parsing is done) must be make sense to the XSLT engine.
Constructs like:
<xsl:for-each select="country[nation='India's']">
<xsl:for-each select="country[nation='India's']">
pass the XML layer but violate the XSLT layer, because in both cases the effective attribute value (as stored in the DOM) is country[nation='India's'], which clearly is an XPath syntax error.
Constructs like:
<xsl:for-each select="country[nation=concat('India', "'", 's')]">
<xsl:for-each select="country[nation=concat("India", "'", "s")]">
clearly violate the XML layer. But they would not violate the XSLT layer (!), since their actual value (if the XSLT document could be parsed in the first place) would come out as country[nation=concat('India', "'", 's')], which is perfectly legal as an XPath expression.
So you must find a way to pass through both layer 1 and layer 2. One way is the variable way as shown above. Another way is:
<xsl:for-each select="country[nation=concat('India', "'", 's')]">
which would appear to XSLT as country[nation=concat('India', "'", 's')].
Personally, I find the "variable way" easier to work with.
Part of the XML:
<text><b>Title</b> <b>Happy</b></text>
In my XSL I have:
<xsl:value-of select="text" disable-output-escaping="yes" />
My output becomes
**TitleHappy**
My spacing went missing - there's supposed to be a space between </b> and <b>.
I tried normalize-space(), it doesn't work.
Any suggestions? Thanks!
if you want whitespace from an xsl, use:
<xsl:text> </xsl:text>
whitespace is only preserved if its recognized as a text node (ie: " a " both spaces will be recognized)
whitespace from the orignal source xml has to be preserved by telling the parser (for example)
parser.setPreserveWhitespace(true);
As your outputting HTML you could substitute your space with a non-breaking space
Do you have any control over the generation of the original XML? If so, you could try adding xml:space="preserve" to the text element which should tell the processor to keep the whitespace.
<text xml:space="preserve"><b>Title</b> <b>Happy</b></text>
Alternatively, try looking at the "xsl:preserve-space" element in XSLT.
<xsl:preserve-space elements="text"/>
Although I have never used this personally, it might of some help. See W3Schools for more information.
thank you for everyone's input.
Currently I am using MattH suggestion which is to test for space and substitue to non-breaking space. Another method I thought of is to test for "</b> <b>" and substitue with " </b><b>". The space contain within a bold tags are actually output. Both methods worked. Don't know what the implications are though. And I still can't figure out why the spacing is removed when it is found between 2 seperate bold tags.
I'll spare you the details because they would be needlessly confusing. Long story short, I'm using XSLT 1.0 to generate XSL documents, I'm trying to compare a variable to a literal string, and that string may contain quotes and apostrophes.
For the sake of simplicity, let's say that this literal is composed of two characters: a quote followed by an apostrophe. In reality, it can be any text really. Is there a simpler way to do this:
<xsl:if test="$var = concat('"', "'")">
than this?
<xsl:variable name="str">"'</xsl:variable>
<xsl:if test="$var = $str">
I have checked XPath's specs and there doesn't seem to be a way to escape characters, so the following would not work as desired:
<xsl:if test="$var = '"''">
Thanks!
There's no way to do it neatly in XPath 1.0. In XPath 2.0, you can escape both kinds of quotes by doubling.
& quot;& amp;&(!)apos; -looks much better, but what did you want to get?
In anyway: once I have written application that deals with producing of Javascript over XSLT.
The same problem with huge number of & quot;,... we solved in 2 ways:
Declare global xsl:param, $q - looks shorter than & quot;
Use 'translate' XPath function, make assumption '!' - is a & quot;, # is a & amp; ..