replaceAll() \r\n in a JSON serialized string

  • 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');
        }
    }
    

    Can you explain a bit more why you want to do this replacement? JSON supports \r\n and most JSON is valid JavaScript too.

    @KeithC - I added some explanation to the original post, thanks.

    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');`

    Alternatively, what if you make the replacement in javascript? `data_jobPostings = JSON.parse( options.jobPostings.replace(/\r\n/g, '\\r\\n') );`

    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.

    You probably just have to do .replaceAll("\\\\r", "") with four slashes rather than two to make it match

  • Keith C

    Keith C Correct answer

    7 years ago

    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>
    

    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} );`

    If I try just {!jobMapJSON} or options = data_jobPostings: {!jobMapJSON}, I get unexpected token errors.

    @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.

    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.

    That's a nice workaround but I wish there was an answer to the question of why \r\n can't be replaced in JSON

License under CC-BY-SA with attribution


Content dated before 7/24/2021 11:53 AM