0

I am hoping this is a simple one, though it seems it often isn't...

I am working with XLST 1.0 and I have a string which I need to translate. This string is a user-entered text field. It contains several smaller strings separated by a delimiter. (In this case, it's "|".) The length of this string and the number of special characters varies widely.

(This field is similar to a CSV list, however, rather than using a comma as the delimiter, the "|" is the delimiter.)

I need to learn how to change this delimiter to <br>.

I've tried using the following XSL to achieve this:

<xsl:variable name="stringtotrans">
    <xsl:text>String1|String2|String3</xsl:text>
</xsl:vairable>
    <!-- In the actual XML document, this variable grabs the value of an attribute. -->
    <!-- For this example, it's being entered manually. -->
    <!-- The number and length of the individual strings varies widely. -->

<xsl:value-of select="translate($stringtotrans, '|', '&#xA;&#xD;')"/>

When this code is run, the output is:

String1String2String3

The expected/desired output is:

String1
String2
String3

Any and all help with this would be greatly appreciated!

Simcik
  • 45
  • 2
  • 10
  • 1
    The `translate()` function can convert a character to another character. It cannot convert a character to a string of two or more characters, or to an element such as `
    `. For this, you would need a recursive template such as the one shown here: http://stackoverflow.com/questions/30339128/how-to-replace-single-quote-to-double-single-quote-in-xslt/30339654#30339654
    – michael.hor257k Mar 07 '16 at 22:41
  • Oh, wonderful... `/sarc` I will examine that example to see if I can solve the issue. In the meantime, are there any alternative methods which can achieve the desired result? – Simcik Mar 07 '16 at 22:55
  • "*are there any alternative methods which can achieve the desired result?*" Not in XSLT 1.0 as such. If your XSLT 1.0 processor supports the EXSLT `str:tokenize()` extension function, then it's a bit easier. -- P.S. You haven't told us exactly what your "desired result" is. -- PP.S. Your sarcasm is misplaced. – michael.hor257k Mar 07 '16 at 23:00
  • Michael, I'm not sure I'm understanding you (in either regard). The desired result is shown above. Each substring, which is in a delimited list, with a delimiter of "|", should appear on it's own line. As for the `/sarc`, that was in reference to the `translate` function's inability to preform translations of any significant value, and the only apparent alternative being a far more complex and involved solution. It was in no way meant to disparage your response, nor was it directed toward you. – Simcik Mar 07 '16 at 23:16
  • 1
    "*The desired result is shown above.*" You say: "*change this delimiter to a newline,
    , or other such character.*" That's ambiguous. If your result is text, then `newline` can mean CR (Mac), LF (Unix) or CRLF (Windows). The first two are single characters, and thus *can* be produced by `translate()`. The last one is not and cannot. If your result is HTML, then you need `
    `. That's not a character, and of course it cannot be returned by the `translate()` function. Given such disparity, you will understand that "*other such character*" is meaningless.
    – michael.hor257k Mar 07 '16 at 23:26
  • I understand now. Thanks for the explanation. The ultimate desired result would be
    , as the final output is in HTML. However, if an intermediary was available that would produce the desired end result using another character, I would like to learn of this as well. For the time being, I'll try implementing your previously suggested method.
    – Simcik Mar 08 '16 at 14:11
  • "*The ultimate desired result would be
    *" I have posted an answer showing how to do that. "*if an intermediary was available that would produce the desired end result using another character*" If it's a single character, then use `translate()`; if it's a string of more than one character, then use the `replace` template I linked to earlier.
    – michael.hor257k Mar 08 '16 at 14:45

2 Answers2

1

The translate() function maps from character to character. In your case, you're replacing | with &#xA; (the first character), which is line feed (LF). This may work on Unix systems where LF commonly marks end of line, but it won't work on Windows, for example, where the end of line marker is CR+LF (&#xD;&#xA;).

For further details on EOLs in XML, see How to add a newline (line break) in XML file?

For replacing a character with a string in XSLT 1.0, see Michael's recursive template for replace.

Community
  • 1
  • 1
kjhughes
  • 106,133
  • 27
  • 181
  • 240
  • I have tried implementing the recursive template and am running into a significant issue. When I implement it, the output is entirely blank. (Even erasing the rest of the output from the previously working XSL.) Thoughts? – Simcik Mar 08 '16 at 16:47
  • You'd need to provide more information on how it's failing (in a new question, please, not a comment), but what's wrong with [Michael's answer here to your specific question](http://stackoverflow.com/a/35870363/290085)? – kjhughes Mar 08 '16 at 16:54
  • I am not sure why it was not working. I may have simply made a typo. Michael's solution is working. Thank you both for your help and explanation! – Simcik Mar 08 '16 at 21:27
1

I need to learn how to change this delimiter to <br>.

The following stylesheet:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="UTF-8" />

<xsl:template match="/">

    <xsl:variable name="stringtotrans">
        <xsl:text>String1|String2|String3</xsl:text>
    </xsl:variable>

    <p>
        <xsl:call-template name="tokenize">
            <xsl:with-param name="text" select="$stringtotrans"/>
        </xsl:call-template>
    </p>
</xsl:template>

<xsl:template name="tokenize">
    <xsl:param name="text"/>
    <xsl:param name="delimiter" select="'|'"/>
    <xsl:choose>
        <xsl:when test="contains($text, $delimiter)">
            <xsl:value-of select="substring-before($text, $delimiter)"/>
            <br/>
            <!-- recursive call -->
            <xsl:call-template name="tokenize">
                <xsl:with-param name="text" select="substring-after($text, $delimiter)"/>
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="$text"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

</xsl:stylesheet>

applied to any XML input, will return:

<p>String1<br>String2<br>String3</p>
michael.hor257k
  • 113,275
  • 6
  • 33
  • 51