tags:

views:

54

answers:

3

I am using XSLT inside of ASP, it's serviced by msxml6.

Incoming XML loaded to the object has "carriage returns" which I think may be ASCII 10. I would like to transform those to <br/> in the output.

I am trying to detect &#10; in the incoming XML, but can't seem to find that. I've tried Javascript (JScript inside of ASP), to no avail.

It's coming from MS Excel spreadsheetML, interestingly.

Ideas on:

  • how it's encoded in the XML object inside msxsm6
  • how to detect, then replace with <br/>?

Thank you everyone, stackoverflow is great!!

A: 

replace(replace(replace(XMLString, vbCrLf, ""), vbCr, ""), vbLf, "")

Sage
+4  A: 

From http://www.w3.org/TR/2008/REC-xml-20081126/#sec-line-ends

XML parsed entities are often stored in computer files which, for editing convenience, are organized into lines. These lines are typically separated by some combination of the characters CARRIAGE RETURN (#xD) and LINE FEED (#xA).

To simplify the tasks of applications, the XML processor MUST behave as if it normalized all line breaks in external parsed entities (including the document entity) on input, before parsing, by translating both the two-character sequence #xD #xA and any #xD that is not followed by #xA to a single #xA character.

So, it's ok to look for &#xA; (or &#10;). But do note that white space only text nodes from the input may or may not be preserve depending on XML tree provider (MSXSL XML parser doesn't preserve this text nodes). Not white space only text nodes are preserved, of course.

Then, this text named template replace new lines with empty br elements in XSLT 1.0:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="text()" name="text">
        <xsl:param name="pString" select="."/>
        <xsl:choose>
            <xsl:when test="contains($pString,'&#xA;')">
                <xsl:call-template name="text">
                    <xsl:with-param name="pString" 
                     select="substring-before($pString,'&#xA;')"/>
                </xsl:call-template>
                <br/>
                <xsl:call-template name="text">
                    <xsl:with-param name="pString" 
                     select="substring-after($pString,'&#xA;')"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$pString"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

With this input:

<root>
<text>
whatever
</text>
<text>and more</text>
</root>

Output:

<root>
<text><br />whatever<br /></text>
<text>and more</text>
</root>
Alejandro
@Alejandro: +1 for a correct answer and good explanation!
Dimitre Novatchev
Yay Alejandro, this was dead on. I'll next post my question about DOCTYPE in msmxl6 which seems to be non-working. Thank you!
Dave
@Dave: You are wellcome! Ask any time.
Alejandro
@Alejandro: The first `<xsl:call-template name="text">` (right after xsl:when) seems a bit redundant since it is known that the parameter shouldn't contain line feed because of `select="substring-before($pString,'')"`. Could you please specify is this just a design issue or am I missing some specific reasons for this. Wouldn't `<xsl:value-of select="substring-before($pString,'')"/>` be simpler?
jasso
@jasso: You are right. It would be more compact to just output the text right there. But, because we tend to think these patterns as FP, the actual output content template is in one place. This allows reuse (Think about further processing)
Alejandro
@Alejandro: Thanks for the clarification. I was just wondering because for some reason creating templates with parameters is a case where I personally tend to make all kinds of stupid simple errors, don't know why...
jasso
A: 

Here is a template I use to do this:

<xsl:template name="nl2br">
        <xsl:param name="contents" />

        <xsl:choose>
                <xsl:when test="contains($contents, '&#10;')">
                        <xsl:value-of select="substring-before($contents, '&#10;')" disable-output-escaping="yes" />
                        <br />
                        <xsl:call-template name="nl2br">
                                <xsl:with-param name="contents" select="substring-after($contents, '&#10;')" />
                        </xsl:call-template>
                </xsl:when>
                <xsl:otherwise>
                        <xsl:value-of select="$contents" disable-output-escaping="yes" />
                </xsl:otherwise>
        </xsl:choose>
</xsl:template>
Louis W
jasso