Take the 2-minute tour ×
Salesforce Stack Exchange is a question and answer site for Salesforce administrators, implementation experts, developers and anybody in-between. It's 100% free, no registration required.

I can't get replaceAll to work on the '\r\n' sequence in a JSON serialized string.

I am serializing a Map object that contains long textarea fields with newlines. I need to change '\r\n' to '\\r\\n' for Javascript purposes. When I serialize the object, I see '\r\n' in the resulting string. However, none of the replaceAll lines that I try will work:

Map<Id, Job_Posting__c> jobMap = new Map<Id, Job_Posting__c>();
// job map gets populated.
String x = JSON.serialize(jobMap);
String y = x.replaceAll('\r\n', '\\r\\n');
String z = x.replaceAll('\\r\\n', '\\\\r\\\\n');

Is there something about JSON serialized strings that force a different approach? I see that the serialized string is between double quotes - does that make a difference?

Details: I want to pass a serialized map of job posting records to a Javascript function in a Visualforce page. The Javascript JSON.parse() fails with "unexpected token" when it hits the '\r\n'. If I manually edit the JSON string to be '\\r\\n' then the parse works.

Here's the Javascript on the VF page:

<script>
    // Define the CCx.pageJobSelection module - can be moved to static resource
    (function (module, $) {
        "use strict";
        var data_jobPostings;

        // intercept the 'submit' action of the HTML form 
        jQuery(document).ready( function ($) {
            //processing here.
        });

        module.initialize = function (options) {
            data_jobPostings = JSON.parse(options.jobPostings);
        };

    })(CCx.pageJobSelection = CCx.pageJobSelection || {}, jQuery);

    // initialize the module
    CCx.pageJobSelection.initialize({
        jobPostings: '{!jobMapJSON}'
    })

</script>

Here's the VF controller:

public with sharing class HL_CCx_JobSelectionController {
    public String jobMapJSON { get; private set; }
    public List<Job_Posting__c> jobs { get; private set; }
    private Map<Id, Job_Posting__c> jobMap = new Map<Id, Job_Posting__c>();

    // Constructor
    public HL_CCx_JobSelectionController() {
        jobs = CCx_JobSelector.selectActiveJobs();
        if (jobs == null) {
            ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.FATAL, 'No jobs postings available.'));
            return;
        }

        jobMap.putAll(jobs);

        // Serialize
        jobMapJSON = JSON.serialize(jobMap);
        jobMapJSON = jobMapJSON.replaceAll('\r\n', '\\r\\n');
    }
}
share|improve this question
    
Can you explain a bit more why you want to do this replacement? JSON supports \r\n and most JSON is valid JavaScript too. –  Keith C Jun 16 at 16:49
    
@KeithC - I added some explanation to the original post, thanks. –  David Cheng Jun 16 at 17:04
    
Once you have an apex string, it shouldn't matter where the string came from. What happens if you do this: (a) get the serialized JSON string from this controller, copy to clipboard, (b) run in anonymous window: String j = 'STRING FROM FIRST STEP'; System.debug(j.replaceAll('\r\n', '\\r\\n'); –  Benj Jun 16 at 17:27
    
Alternatively, what if you make the replacement in javascript? data_jobPostings = JSON.parse( options.jobPostings.replace(/\r\n/g, '\\r\\n') ); –  Benj Jun 16 at 17:30
    
When I do that in Apex I get 'rn', when I do the replace in Javascript I don't get any errors, but there's no line break between the text lines. –  David Cheng Jun 16 at 18:21

2 Answers 2

up vote 3 down vote accepted

Why not just emit the JSON into the page so it is immediately parsed by JavaScript:

CCx.pageJobSelection.initialize(
    {!jobMapJSON}
);

and then there is no need to parse yourself:

module.initialize = function (options) {
    data_jobPostings = options;
};

This should avoid the need for any replacing.

Its also worth using JSON.serializePretty to make the JSON easier to manually review when you do a "View Page Source" of the page.

PS

This page:

<apex:page controller="AbcController">
<script>
var map = {!jsonString};
alert(map);
</script>
</apex:page>

and controller (where cve__OccupationalDescription__c is a custom text area field):

public class AbcController {
    public String jsonString {
        get {
            return JSON.serializePretty(new Map<Id, Contact>([
                    select Id, FirstName, LastName, cve__OccupationalDescription__c
                    from Contact
                    limit 2
                    ]));
        }
    }
}

produce this valid JSON that the browser's JavaScript engine is happy with:

<script>
var map = {
  "003A000000ou3XLIAY" : {
    "attributes" : {
      "type" : "Contact",
      "url" : "/services/data/v30.0/sobjects/Contact/003A000000ou3XLIAY"
    },
    "cve__OccupationalDescription__c" : "Line 1.\r\nLine 2.\r\nLine 3.",
    "RecordTypeId" : "012A0000000zC62IAE",
    "FirstName" : "Tim",
    "Id" : "003A000000ou3XLIAY",
    "LastName" : "Jones"
  },
  "003A000000pm2plIAA" : {
    "attributes" : {
      "type" : "Contact",
      "url" : "/services/data/v30.0/sobjects/Contact/003A000000pm2plIAA"
    },
    "RecordTypeId" : "012A0000000zC62IAE",
    "FirstName" : "Derek",
    "Id" : "003A000000pm2plIAA",
    "LastName" : "O'Brien"
  }
};
alert(map);
</script>
share|improve this answer
    
if the OP wants to pass in an options object (rather than a single data value), it could also work like this: CCx.pageJobSelection.initialize( options = data_jobPostings: {!jobMapJSON} ); –  Benj Jun 16 at 17:58
    
If I try just {!jobMapJSON} or options = data_jobPostings: {!jobMapJSON}, I get unexpected token errors. –  David Cheng Jun 16 at 18:19
    
@DavidCheng Perhaps you can post what "View Page Source" shows you and the specific error message? I just added a working example to the answer. –  Keith C Jun 16 at 18:51
    
@Keith C: thanks I'll try it. –  David Cheng Jun 16 at 19:07
    
Thanks, I went back to your original code snippets and it worked. I had extra curly braces in the initialize method that caused the unexpected token error. –  David Cheng Jun 16 at 20:04
final String CRLF = '\r\n';

String x = '\r\n';
String expected = '\\r\\n';

System.assertEquals(expected, x.replaceAll(CRLF, '\\\\r\\\\n'));
share|improve this answer
    
Alan - if you serialize x, then it doesn't work. –  David Cheng Jun 16 at 17:10

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.