¿Usar una variable dentro de un bloque CDATA, en Javascript?

CDATA-blocks work great for coding large blocks of HTML, or CSS, into strings. But, I can't figure out how to use a variable-value within one.

For example, consider this JavaScript code:

var FullName    = "Friedrich Hayek";
var ProfileCode = (<><![CDATA[
                    <div id="BigHonkingChunkO_HTML">
                        ...Lot's o' code...

                        Name: $FullName$
                        Birth: $Birthdate$

                        ...Lot's o' code...

                        ... $FullName$ ...

                        ...Lot's o' code...
                ]]></>).toString ();

Como lo consigo $FullName$ to render as "Friedrich Hayek" instead of "$FullName$"?

Note that there is more than one variable and each variable can be used a few times in the CDATA block.

Alternate code sample:

var UserColorPref   = "red";
var UI_CSS          = (<><![CDATA[
                        body {
                            color:              $UserColorPref$;
                    ]]></>).toString ();

Looking to set the color attribute to red.

preguntado el 09 de enero de 11 a las 02:01

3 Respuestas

Is it elegant enough ?

function replaceVars(content, vars)
    return content.replace(/\$(\w+)\$/g, function($0, $1)
        return ($1 in vars ? vars[$1] : $0);

ProfileCode = replaceVars(ProfileCode, {"FullName" : "Friedrich Hayek"});

In case associative keys don't really matter, you can always opt to use:
sprintf or vsprintf


What about making the 2nd parameter optional ?

function replaceVars(content, scope) {
    if (!scope || typeof scope != "object") {
        scope = this;

    return content.replace(/\$(\w+)\$/g, function($0, $1) {
        return ($1 in scope ? scope[$1] : $0);

// example1
var FullName = "Friedrich Hayek";
ProfileCode = replaceVars(ProfileCode);

// example2
var vars = {"FullName" : "Friedrich Hayek"};
ProfileCode = replaceVars(ProfileCode, vars);

Respondido 17 Jul 11, 17:07

replaceVars() is elegant yes. Calling it is a little more clunky than the sprintf()-like version of the function. +1. - Brock Adams

That's easier to use, and a fine alternative. But making the 2nd parameter optional can obscure the code. Just seeing ProfileCode = replaceVars(ProfileCode); means that the developer has to examine ProfileCode in minute detail, and then scan the whole JS code, to see what's replacing what! ... The first version of the function, and the function we ended up using, both self-document their intentions, right at the function call level. - Brock Adams


Respondido el 09 de enero de 11 a las 06:01

That's kinda kludgy and doesn't scale gracefully. In the actual live code, there are currently 8 variables in play. I'm hoping for a more inline solution. - Brock Adams

Use array, to map variable names to values and replace them while iterating through a loop. - Ratna Dinakar

Después de fregar the CDATA spec, this "CDATA Confusion" article, it seems that CDATA sections treat everything as pure text, except for character-data entities and the section end marker (]]>). For example,

var x = $('<!DOCTYPE X[<!ENTITY foo "BAR">]><z> cc &#65; &foo;</z>');
console.log ($(x, 'z').text() );

Rendimientos: ]> cc A &foo;

So, there's no way to have variable substitution within a CDATA section. The best we can do is start and stop the sections, like so:

var FullName    = "Friedrich Hayek";
var ProfileCode = (<><![CDATA[
                    <div id="BigHonkingChunkO_HTML">
                        ...Lot's o' code...

                        Name: ]]></>).toString () + FullName+ (<><![CDATA[

                        ...Lot's o' code...
                ]]></>).toString ();
console.log (ProfileCode);

-- which is obviously not acceptable.

Practical workaround:

It won't help anyone looking for a CDATA solution (which we now know is impossible, per the spec). But as we were just using CDATA as a method to generate a complex string, then we can clean the string up afterwards, per Ratna Dinakar's answer.

The function we ended up using is:

function sSetVarValues (sSrcStr, sReplaceList /* , Variable */)
/*--- function sSetVarValues takes a string and substitutes marked
    locations with the values of the variables represented.
    Conceptually, sSetVarValues() operates a little like sprintf().

        sSrcStr         --  The source string to be replaced.   
        sReplaceList    --  A string containing a comma-separated list of variable
                            names expected in the raw string.  For example, if 
                            sReplaceList was "Var_A", we would expect (but not require)
                            that sSrcStr contained one or more "$Var_A$" substrings.
        *Variable*      --  A variable-length set of parameters, containing the values
                            of the variables specified in sReplaceList.  For example,
                            if sReplaceList was "Var_A, Var_B, Var_C", then there better 
                            be 3 parameters after sReplaceList in the function call. 
    Returns:                The replaced string.
    if (!sSrcStr)       return null;
    if (!sReplaceList)  return null;

    var aReplaceList    = sReplaceList.split (/,\s?/);

    for (var J = aReplaceList.length-1;  J >= 0;  --J)
        var zRepVar     = new RegExp ('\\$' + aReplaceList[J] + '\\$', "g");
        sSrcStr         = sSrcStr.replace (zRepVar, arguments[J+2]);
    return sSrcStr;

Uso de muestra:

var AAA     = 'first';
var BBB     = 'second'; 
var CCC     = 'third';
var Before  = "1 is $AAA$, 2 is $BBB$, 3 is $CCC$";

var After   = sSetVarValues (Before, "AAA, BBB, CCC", AAA, BBB, CCC);

console.log (Before);
console.log (After);


    1 is $AAA$, 2 is $BBB$, 3 is $CCC$
    1 is first, 2 is second, 3 is third

Respondido 17 Jul 11, 10:07

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.