I want to implement carriage return within xslt.
The problem is I have a varible:
Step 1 = Value 1 breaktag Step 2 = Value 2 as a string and would like to appear as
Step 1 = Value 1
Step 2 = Value 2
in the HTML form but I am getting the br tag on the page.Any good ways of implementing a line feed/carriage return in xsl would be appreciated
As an alternative to
<xsl:text>
</xsl:text>
you could use
<xsl:text>
</xsl:text> <!-- newline character -->
or
<xsl:text>
</xsl:text> <!-- carriage return character -->
in case you don't want to mess up your indentation
This works for me, as carriage-return + life feed.
<xsl:text>
</xsl:text>
The "
" string does not work.
The cleanest way I've found is to insert !ENTITY declarations at the top of the stylesheet for newline, tab, and other common text constructs. When having to insert a slew of formatting elements into your output this makes the transform sheet look much cleaner.
For example:
<?xml version="1.0"?>
<!DOCTYPE xsl:stylesheet [
<!ENTITY nl "<xsl:text>
</xsl:text>">
]>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="step">
&nl;&nl;
<xsl:apply-templates />
</xsl:template>
...
</xsl:stylesheet>
use a simple carriage return in a xsl:text element
<xsl:text>
</xsl:text>
Try this at the end of the line where you want the carriage return. It worked for me.
<xsl:text><![CDATA[<br />]]></xsl:text>
I was looking for a nice solution to this, as many would prefer, without embedding escape sequences directly in the expressions, or having weird line breaks inside of a variable. I found a hybrid of both this approaches actually works, by embedding a text node inside a variable like this:
<xsl:variable name="newline"><xsl:text>
</xsl:text></xsl:variable>
<xsl:value select="concat(some_element, $newline)" />
Another nice side-affect of this is that you can pass in whatever newline you want, be it just LF, CR, or both CRLF.
--Daniel
Here is an approach that uses a recursive template, which looks for
in the string from the database and then outputs the substring before.
If there is a substring after
remaining, then the template calls itself until there is nothing left.
In case
is not present then the text is simply output.
Here is the template call (just replace #ActivityExtDescription with your database field):
<xsl:call-template name="MultilineTextOutput">
<xsl:with-param name="text" select="#ActivityExtDescription" />
</xsl:call-template>
and here is the code for the template itself:
<xsl:template name="MultilineTextOutput">
<xsl:param name="text"/>
<xsl:choose>
<xsl:when test="contains($text, '
')">
<xsl:variable name="text-before-first-break">
<xsl:value-of select="substring-before($text, '
')" />
</xsl:variable>
<xsl:variable name="text-after-first-break">
<xsl:value-of select="substring-after($text, '
')" />
</xsl:variable>
<xsl:if test="not($text-before-first-break = '')">
<xsl:value-of select="$text-before-first-break" /><br />
</xsl:if>
<xsl:if test="not($text-after-first-break = '')">
<xsl:call-template name="MultilineTextOutput">
<xsl:with-param name="text" select="$text-after-first-break" />
</xsl:call-template>
</xsl:if>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text" /><br />
</xsl:otherwise>
</xsl:choose>
Works like a charm!!!
I believe that you can use the xsl:text tag for this, as in
<xsl:text>
</xsl:text>
Chances are that by putting the closing tag on a line of its own, the newline is part of the literal text and outputted as such.
I separated the values by Environment.NewLine and then used a pre tag in html to emulate the effect I was looking for
This is the only solution that worked for me. Except I was replacing
with \r\n
Related
I need to to process a delimited text with xslt that looks like:
abc#mail;#6896;#def#mail;#7467;#hij#mail
The output should be a mailto: link with all addresses and I need to throw away the numbers between them. I am working on Sharepoint, so can only use XSLT 1.0
Edit:
I found this question from about 7 years ago, that is almost the same:
"Regular expression"-style replace in XSLT 1.0
In my case, it doing exactly the opposite: keeping the numbers and throwing out the mail addresses. Can someone help me how to modify the code in the address?
update: as a workaround, I added the delimiter as prefix to my text, and the template works perfect.
This specifically looks for numbers rather than skipping every other item.
<xsl:template name="ExtractNumbers">
<xsl:param name="strInputString"/>
<xsl:variable name="strCurrent" select="substring-before($strInputString, ';#')" />
<xsl:variable name="strRemaining" select="substring-after($strInputString, ';#')" />
<xsl:if test="$strCurrent != ''">
<xsl:if test="string(number($strCurrent)) != 'NaN'">
<xsl:value-of select="$strCurrent" />
<xsl:if test="contains($strRemaining, ';#')">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:if>
<xsl:call-template name="ExtractNumbers">
<xsl:with-param name="strInputString" select="$strRemaining"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
Is there an easy way to indent whole blocks of text in XSL? I'd like to indent blocks of text to roughly match the nested levels of the XML.
The answer here, XSL: output of "nested" structures
proposes an indent parameter which is increased as you recurse down.
This is a good start, but requires a long <value-of> tag at the beginning of every line, which of course can't be put inside of the <xsl:text> block.
So, is there a way to use that to indent a multi-line <xsl:text> block? I don't want to have to wrap every single line separately into <xsl:text> blocks, just so that I can add a variable to the beginning of each line.
Example template:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="drv">
<xsl:param name="pIndent"/>
<xsl:text>
Column {
anchors { left: parent.left; right: parent.right }
</xsl:text>
<xsl:apply-templates select="snc|kap">
<xsl:with-param name="pIndent" select="concat($pIndent, ' ')"/>
</xsl:apply-templates>
<xsl:text>
}</xsl:text>
</xsl:template>
</xsl:stylesheet>
So, I want to be able to output the text at the appriate indentation level. So, is there a way to dynamically indent the whole <xsl:text> block (or blocks in this case)? This will allow the output code to be indented correctly, making it much easier for me to debug.
Output like this, but indented to the correct level in the surrounding code:
Column {
anchors { left: parent.left; right: parent.right }
[Code from some other template
kept at this indent level]
}
I'll try and summarise the question in a couple of different ways, as people are struggling to understand it:
Given a level of indentation known at runtime, how can you indent the contents of an entire <xsl:text> block to that level?
Or alternatively: Given a value known at runtime, how can you prepend the value to the beginning of every line in an <xsl:text> block?
You essentially want a "function" that can take a string and prepend a particular prefix to the start of the string and also immediately after every newline character that the string contains. In XSLT 2.0 this would be very simple using the regular expression replace function, but unfortunately lxml only supports XSLT 1.0.
In XSLT 1.0 I'd approach this using a tail-recursive named template:
<xsl:template name="printIndented">
<xsl:param name="text" />
<xsl:param name="indent" />
<xsl:if test="$text">
<xsl:value-of select="$indent" />
<xsl:variable name="thisLine" select="substring-before($text, '
')" />
<xsl:choose>
<xsl:when test="$thisLine"><!-- $text contains at least one newline -->
<!-- print this line -->
<xsl:value-of select="concat($thisLine, '
')" />
<!-- and recurse to process the rest -->
<xsl:call-template name="printIndented">
<xsl:with-param name="text" select="substring-after($text, '
')" />
<xsl:with-param name="indent" select="$indent" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text" />
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
To use the "function" you'd have to do something like
<xsl:call-template name="printIndented">
<xsl:with-param name="indent" select="$pIndent" />
<xsl:with-param name="text"
>Column {
anchors { left: parent.left; right: parent.right }</xsl:with-param>
</xsl:call-template>
<xsl:apply-templates select="snc|kap">
<xsl:with-param name="pIndent" select="concat($pIndent, ' ')"/>
</xsl:apply-templates>
<xsl:call-template name="printIndented">
<xsl:with-param name="indent" select="$pIndent" />
<xsl:with-param name="text">}</xsl:with-param>
</xsl:call-template>
Of course, you then have to be extremely careful not to use an auto-formatter on the XSLT source code itself, as that would throw all your carefully indented code out of the window...
I've got a string that could have line breaks and apostrophes. I need to do a replace for both. I have the following xsl code:
<xsl:call-template name="replaceapostrophes">
<xsl:with-param name="string">
<xsl:call-template name="replacelinefeeds">
<xsl:with-param name="string" select="hl7:text/hl7:paragraph"/>
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
<!-- template for replacing line feeds with <br> tags for page display -->
<xsl:template name="replacelinefeeds">
<xsl:param name="string"/>
<xsl:choose>
<xsl:when test="contains($string,'
')">
<xsl:value-of select="substring-before($string,'
')"/>
<br/>
<xsl:call-template name="replacelinefeeds">
<xsl:with-param name="string" select="substring-after($string,'
')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$string"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- template for replacing html encoded apostrophes for page display -->
<xsl:template name="replaceapostrophes">
<xsl:param name="string"/>
<xsl:choose>
<xsl:when test="contains($string, ''')">
<xsl:value-of select="substring-before($string,''')"/>'<xsl:call-template name="replaceapostrophes">
<xsl:with-param name="string" select="substring-after($string,''')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$string"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
This is the xml code:
<text>
<paragraph>Adding apostrophe to the patient's instructions
and checking for a second line</paragraph>
</text>
However, when this runs, I'm getting the apostrophe accounted for, but not the line breaks.
Adding apostrophe to the patient's instructions and checking for a second line
rather than
Adding apostrophe to the patient's instructions
and checking for a second line
It does work fine if there's one or the other but not both in the same string.
Is there a different way I need to do these?
Thanks
Try doing it the other way around (replace apostrophes first, then line breaks).
Basically you are putting an HTML <br/> element into your variable, and then taking its text value to replace the apostrophes , which removes the line break again.
Use the templates the other way round, i.e. first replace the apostrophes, then the line feeds. And make sure for the result of the replacement of line feeds you use xsl:copy-of and not xsl:value-of when you output it, as otherwise the br elements will be lost. So in case you have <xsl:variable name="text"><xsl:call-template name="replacelinefeeds">..</xsl:call-template></xsl:variable>, make sure you use <xsl:copy-of select="$text"/>.
Hi I have the below line in by XML and also I need a hyperlink for the number. I want this output to be shown in HTML format.
<main>
<alph>a b 2,3</alph>
</main>
I want an XSLT that gives output as:
a b 2, a b 3
I have tried the below XSLT:
<xsl:template match="alph">
<xsl:variable name="link" select="normalize-space(translate(
normalize-space(current()),abcdefghijklmnopqrstuvwxyz,''))"/>
<xsl:value-of select="substring-before(normalize-space(.),$link)"/>
<xsl:variable name="tex">
<xsl:value-of select="text()"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="contains($link,',')">
<xsl:variable name="new">
<xsl:value-of select="tokenize($link,',')"/>
</xsl:variable>
<xsl:value-of select="concat($new,$tex)"/>
</xsl:when>
<xsl:when test="contains($link,'-')">
<xsl:value-of select="tokenize($link,'-')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$link"/>
</xsl:otherwise>
</xsl:choose>
But it is giving me output as:
a b 2 3a b 2,3
Thanks
One problem you have is with the variable link
<xsl:variable name="link" select="normalize-space(translate(
normalize-space(current()),abcdefghijklmnopqrstuvwxyz,''))"/>
It looks like you are trying removing all alphabetic characters from the string, so that you are left with just 2,3. However, for this to work the abc...xyz needs to be enclosed in apostrophes, otherwise it will be looking for an element named abc...xyz. Having said that, you say you are using XSLT2.0, so you can make use of the replace function here, which takes a regular expression as a parameter
<xsl:variable name="link" select="normalize-space(replace(current(),'[a-z]',''))"/>
Next, you can get the text before this link, like so
<xsl:variable name="text" select="normalize-space(substring-before(current(), $link))"/>
This will give you your a b
Finally, you can use the tokenize function to split up the 2,3. In your XSLT you seem to be looking for hyphens too, but the tokenize function also uses regular expressions, so this is not a problem. What you can do is just tokenize the string, and re-join it using the text variable as a separator
<xsl:value-of select="concat($text, ' ')"/>
<xsl:value-of select="tokenize($link,',|-')" separator="{concat(', ', $text, ' ')}"/>
Here is the full XSLT
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="alph">
<xsl:variable name="link" select="normalize-space(replace(current(),'[a-z]',''))"/>
<xsl:variable name="text" select="normalize-space(substring-before(current(), $link))"/>
<xsl:value-of select="concat($text, ' ')"/>
<xsl:value-of select="tokenize($link,',|-')" separator="{concat(', ', $text, ' ')}"/>
</xsl:template>
</xsl:stylesheet>
When applied on your XML, the following is output
a b 2, a b 3
I am rendering a list of tickers to html via xslt and I would like for the list to be comma deliimited. Assuming I was going to use xsl:for-each...
<xsl:for-each select="/Tickers/Ticker">
<xsl:value-of select="TickerSymbol"/>,
</xsl:for-each>
What is the best way to get rid of the trailing comma? Is there something better than xsl:for-each?
<xsl:for-each select="/Tickers/Ticker">
<xsl:if test="position() > 1">, </xsl:if>
<xsl:value-of select="TickerSymbol"/>
</xsl:for-each>
In XSLT 2.0 you could do it (without a for-each) using the string-join function:
<xsl:value-of select="string-join(/Tickers/Ticker, ',')"/>
In XSLT 1.0, another alternative to using xsl:for-each would be to use xsl:apply-templates
<xsl:template match="/">
<!-- Output first element without a preceding comma -->
<xsl:apply-templates select="/Tickers/Ticker[position()=1]" />
<!-- Output subsequent elements with a preceding comma -->
<xsl:apply-templates select="/Tickers/Ticker[position()>1]">
<xsl:with-param name="separator">,</xsl:with-param>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="Ticker">
<xsl:param name="separator" />
<xsl:value-of select="$separator" /><xsl:value-of select="TickerSymbol" />
</xsl:template>
I know you said xsl 2.0 is not an option and it has been a long time since the question was asked, but for all those searching for a posibility to do what you wanted to achieve:
There is an easier way in xsl 2.0 or higher
<xsl:value-of separator=", " select="/Tickers/Ticker/TickerSymbol" />
This will read your /Tickers/Ticker elements and insert ', ' as separator where needed
If there is an easier way to do this I am looking forward for advice
Regards Kevin