tags:

views:

449

answers:

4

I have an XML document, something like

<root>
  <item>_x0034_SOME TEXT</item>
  <item>SOME_x0020_TEXT</item>
  <item>SOME_x0020_TEXT_x0032_</item>
</root>

I'm exporting it to HTML, but I have problems replacing escape characters. I have found several templates in the web to do text replacing but they all are similar to this:

<xsl:template name="replaceString">
    <xsl:param name="strOrig"/>
    <xsl:param name="strSearch"/>
    <xsl:param name="strReplace"/>
    <xsl:choose>
        <xsl:when test="contains($strOrig, $strSearch)">
            <xsl:value-of select="substring-before($strOrig, $strSearch)"/>
            <xsl:value-of select="$strReplace"/>
            <xsl:call-template name="replaceString">
                <xsl:with-param name="strOrig" select="substring-after($strOrig, $strSearch)"/>
                <xsl:with-param name="strSearch" select="$strSearch"/>
                <xsl:with-param name="strReplace" select="$strReplace"/>
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="$strOrig"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

I'm not sure how I can use this to do the multiple replacements. I have tried this:

<xsl:for-each select="PinnacleSys.PMC.Plugins.PVR.PvrChannelDescriptorWrapper/PinnacleSys.PMC.Plugins.PVR.DVBTPvrChannelDescriptor">

    <!--name="<xsl:value-of select="replace(replace(Name, '_x0020_', ' '), '_x0034_', '3')"/>" -->
    <!--name="<xsl:value-of select="Name"/>"-->
    <xsl:variable name="var1" select="Text" />
        <xsl:value-of select="replace($FeatureInfo,'Feature=','TESTING')"/>

    name="
        <xsl:call-template name="replaceString">
            <xsl:with-param name="strOrig" select="Name"/>
            <xsl:with-param name="strSearch" select="'_x0020_'"/>
            <xsl:with-param name="strReplace" select="' '"/>
        </xsl:call-template>
        <xsl:call-template name="replaceString">
            <xsl:with-param name="strOrig" select="Name"/>
            <xsl:with-param name="strSearch" select="'_x0030_'"/>
            <xsl:with-param name="strReplace" select="'0'"/>
        </xsl:call-template>
       ..."

But this just concatenates the string several times, each with a different replacement. I have also investigated variables; if I could assign the result of a template call to a variable, I could get a dirty-but-works solution, which is enough for me. However I haven't been able and don't know if it's possible.

What's the best way to do this?

I'm restricted to 1.0 XSLT (with 2.0 I could call one replace() inside another).

+1  A: 

XSLT 1.0 is not the best at string replacing. The template you have would be the one to use. However, for string replaces, I use string replace in another language, typically JavaScript or C#/VB.NET (Java or any other language would work too). Presumably, at some point, the XML document is serialized to a string. Once it's a string, use a simple string-to-string replace or regular expressions for more complex pattern matching.

Doug D
As I just said up there, I am using IE8 parsing capabilities, to avoid programming. So I won't try this if I find a native XSLT solution. But thanks.
Jaime Pardos
A native XSLT solution is given in my later answer.
Doug D
+1  A: 

Place call of template inside variable body.

<xsl:variable name="myVar"><xsl:call-template name="replaceString">
        <xsl:with-param name="strOrig" select="Name"/>
        <xsl:with-param name="strSearch" select="'_x0020_'"/>
        <xsl:with-param name="strReplace" select="' '"/>
    </xsl:call-template>
</xsl:variable>

This assign to myVar content of call.

Dewfy
I've been able to solve my problem with this. It's dirty as shit but it works.Thank you a lot.Will wait some time for a cleaner solution before accepting your answer.
Jaime Pardos
@Jaime Pardos you are welcome
Dewfy
+1  A: 

Take a look at regular expression support in EXSLT (www.exslt.org). EXSLT support is available in most modern XSL processors.

Jim Garrison
+1  A: 

For a native XSLT 1.0 solution using a template for replacement, the individual replacements need to be nested, as shown here. This obviously isn't efficient due to the potential number of replacements. An optimized version is given below.

<xsl:template match="item">
<xsl:copy>
    <xsl:call-template name="replace-substring">
        <xsl:with-param name="original">
            <xsl:call-template name="replace-substring">
                <xsl:with-param name="original">
                    <xsl:call-template name="replace-substring">
                        <xsl:with-param name="original" select="."/>
                        <xsl:with-param name="substring" select="'_x0020_'"/>
                        <xsl:with-param name="replacement" select="' '"/>
                    </xsl:call-template>
                </xsl:with-param>
                <xsl:with-param name="substring" select="'_x0032_'"/>
                <xsl:with-param name="replacement" select="'2'"/>
            </xsl:call-template>
        </xsl:with-param>
        <xsl:with-param name="substring" select="'_x0034_'"/>
        <xsl:with-param name="replacement" select="'4'"/>
    </xsl:call-template>
</xsl:copy>
</xsl:template>

<xsl:template name="replace-substring">
<xsl:param name="original"/>
<xsl:param name="substring"/>
<xsl:param name="replacement" select="''"/>
<xsl:choose>
    <xsl:when test="contains($original, $substring)">
        <xsl:value-of select="substring-before($original, $substring)"/>
        <xsl:copy-of select="$replacement"/>
        <xsl:call-template name="replace-substring">
            <xsl:with-param name="original" select="substring-after($original, $substring)"/>
            <xsl:with-param name="substring" select="$substring"/>
            <xsl:with-param name="replacement" select="$replacement"/>
        </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
        <xsl:value-of select="$original"/>
    </xsl:otherwise>
</xsl:choose>
</xsl:template>

Since the output is HTML (XML would be fine too), the _xNNNN_ strings can be converted to their hex numeric character references, e.g., &#xNNNN;. This template is efficient.

<xsl:template match="item">
<xsl:copy>
    <xsl:call-template name="replaceChars">
        <xsl:with-param name="original" select="."/>
    </xsl:call-template>
</xsl:copy>
</xsl:template>

<xsl:template name="replaceChars">
<xsl:param name="original"/>
<xsl:choose>
    <xsl:when test="contains($original, '_x')">
        <xsl:value-of select="substring-before($original, '_x')"/>
        <xsl:variable name="after" select="substring-after($original, '_x')"/>
        <xsl:variable name="char" select="substring-before($after, '_')"/>
        <xsl:value-of select="concat('&amp;#x',$char,';')" disable-output-escaping="yes"/>
        <xsl:call-template name="replaceChars">
            <xsl:with-param name="original" select="substring-after($after, '_')"/>
        </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
        <xsl:value-of select="$original"/>
    </xsl:otherwise>
</xsl:choose>
</xsl:template>

This is the resulting output.

<root>
    <item>&#x0034;SOME TEXT</item>
    <item>SOME&#x0020;TEXT</item>
    <item>SOME&#x0020;TEXT&#x0032;</item>
</root>
Doug D
Thank you, this really did the trick.
Jaime Pardos
You're welcome.
Doug D