Showing results for 
Search instead for 
Did you mean: 
Sign up Log in
Deleted user
0 / 0 points
badges earned

Your Points Tracker
  • Global
  • Feed

Badge for your thoughts?

You're enrolled in our new beta rewards program. Join our group to get the inside scoop and share your feedback.

Join group
Give the gift of kudos
You have 0 kudos available to give
Who do you want to recognize?
Why do you want to recognize them?
Great job appreciating your peers!
Check back soon to give more kudos.

Past Kudos Given
No kudos given
You haven't given any kudos yet. Share the love above and you'll see it here.

It's not the same without you

Join the community to find out what other Atlassian users are discussing, debating and creating.

Atlassian Community Hero Image Collage

getting error while accessing key value from the json data in script runner confluence

Hi Team

I am trying to retrieve the key values from the JSON data in the confluence script runner.

but i am getting the below error.

groovy.json.JsonException: expecting '}' or ',' but got current char 's' with an int value of 115 The current character read is 's' with an int value of 115 expecting '}' or ',' but got current char 's' with an int value of 115 line number 9 index number 217 "value": "<at:declarations /><ac:structured-macro ac:name="section" ac:schema-version="1" ac:macro-id="8d7755f6-be87-4926-80d6-9561a0002bf0"><ac:rich-text-body><p><ac:task-list> .......................................................................^ at


Anyone please help me to resolve this.



1 answer

1 accepted

0 votes
Answer accepted

Hi @Sushma ,

The issue might be related to the way you are reading / parsing the JSON. If possible, could you please share the JSON you are parsing and the method you are using to parse it?

You could attempt on running the following:

import groovy.json.JsonSlurper;
new JsonSlurper().setType(JsonParserType.LAX).parseText(index)

The important thing is to change the string format to correct JSON (e.g key with quotes) or you can change JsonSlurper's parser type as mentioned above.

Kind regards,

Hi @Rafael Pinto Sperafico 

import groovy.json.JsonSlurper
String responsestring = '''
"id": "13336836",
"type": "page",
"status": "current",
"title": "LCMDEV-153 : one storydf",
"body": {
"storage": {
"value": "<at:declarations /><ac:structured-macro ac:name=\"section\" ac:schema-version=\"1\" ac:macro-id=\"8d7755f6-be87-4926-80d6-9561a0002bf0\"><ac:rich-text-body><p><ac:task-list>\n <ac:task>\n <ac:task-id>3</ac:task-id>\n <ac:task-status>incomplete</ac:task-status>\n <ac:task-body>Workunit sequence, frequency, and task order has been configured for all environments (CA7, Local) </ac:task-body>\n </ac:task>\n</ac:task-list>\n<ac:task-list>\n <ac:task>\n <ac:task-id>3</ac:task-id>\n <ac:task-status>incomplete</ac:task-status>\n <ac:task-body>Story met acceptance criteria</ac:task-body>\n </ac:task>\n</ac:task-list>\n<ac:task-list>\n <ac:task>\n </p></ac:rich-text-body></ac:structured-macro>",
"representation": "storage",
"_expandable": {
"content": "/rest/api/content/13336836"
"_expandable": {
"editor": "",
"view": "",
"export_view": "",
"styled_view": "",
"anonymous_export_view": ""
"extensions": {
"position": "none"
"_expandable": {
"container": "/rest/api/space/TEST",
"metadata": "",
"operations": "",
"children": "/rest/api/content/13336836/child",
"restrictions": "/rest/api/content/13336836/restriction/byOperation",
"history": "/rest/api/content/13336836/history",
"ancestors": "",
"version": "",
"descendants": "/rest/api/content/13336836/descendant",
"space": "/rest/api/space/TEST"
"_links": {
"self": "http://URL:8090/rest/api/content/13336836",
"base": "http://URL:8090",
"context": "",
"collection": "/rest/api/content",
"webui": "/display/TEST/LCMDEV-153+%3A+one+storydf",
"edit": "/pages/resumedraft.action?draftId=13336836",
"tinyui": "/x/BIHL"
JsonSlurper jsonSlurper = new JsonSlurper()
def jsonobject = jsonSlurper.parseText(responsestring)
assert jsonobject instanceof Map
String val1 = jsonobject.get("id")


I am using the above JSON .

My aim is to retrieve "<ac:task-status>" which is in the "value" section .

Is it possible do ?




Hi @Sushma ,

You could be doing the following:

// replace double-quotes from value with single-quotes
responsestring = responsestring.replaceAll("=\"(.*)\"","='${1}'");

// parse to JSON
def jsonobject = new JsonSlurper().setType(JsonParserType.LAX).parseText(responsestring)

// get the value property
String propertyValue =;

// extract status from status>....< tag
def status = (propertyValue =~ /status>(.+)</);


// Output: incomplete

Kind regards,

Like Sushma likes this

Thanks alot @Rafael Pinto Sperafico 

I will try with the above code..



Hi @Rafael Pinto Sperafico 

I changed to 

String propertyValue = jsonobject.getAt("body").getAt("storage").getAt("value")

Thank you

Kind Regards


Hi @Rafael Pinto Sperafico ,

I have one query,

def propertyValue = jsonobject.getAt("body").getAt("storage").getAt("value")

def status = (propertyValue =~ /status>(.+)</);
def body = (propertyValue =~ /body>(.+)</);

for(int i=0;i<status.size();i++){[i][1])
for(int i=1;i<body.size();i++){[i][1])

the above code will print list of status and body items.

But there is no correlation between the status and body.

is there any way to get task-status and corresponding task-body in a single data structure ?

Thanks in advance

Kind regards


Hi @Rafael Pinto Sperafico 

What I meant is based on task-id is it possible to get the task-status and corresponding task-body ?



Hi @Sushma ,

Perhaps you should consider converting the "XML" provided into a readable XML, so you can iterate over it getting the information you required. For that, you could either:

Please, comment on and document an XSD / DTD for Confluence markup 

Kind regards,

Hi @Rafael Pinto Sperafico 

As you suggested,I converted the xhtml content to valid xml using replaceAll().

JsonSlurper jsonSlurper = new JsonSlurper()
responsestring = responsestring.replaceAll("=\"(.*)\"","='${1}'");
def jsonobject = new JsonSlurper().setType(JsonParserType.LAX).parseText(responsestring)
LazyValueMap propertyValue = jsonobject.getAt("body").getAt("storage") as LazyValueMap
Map.Entry<String,Value>[] items = propertyValue.items()
String value = items[0].getValue()
String xml = value.replaceAll(":","")
xml = StringUtils.substringBetween(xml, "<acrich-text-body>", "</acrich-text-body>");
def slurper = new XmlSlurper().parseText(xml)

as a result I am getting the below output :

1incompleteWorkunit sequence, frequency, and task order has been configured for all environments (CA7, Local) 2incompleteStory met acceptance criteria3incompleteBatch list selection criteria to be tested for correctness and for performance4incompleteScreen Knowledge base should be updated (if required UI Specs)5incompleteAll Impacted Regression tests passed in Master Nightly pipeline6incompleteManual unit testing should be completed for UI Look & Feel, navigation, validation and screen resolution

How to get the individual tasklist body based on the id ?

please help me ..

Kind Regards


Hi @Sushma ,

Here is an example:

<task-body>Workunit sequence, frequency, and task order has been configured for all environments (CA7, Local) </task-body>
<task-body>Story met acceptance criteria</task-body>

You could run the following:

slurper.getAt("task-list").'*'.find {
it ->
println(" ---------- ")

Resulting on:

Workunit sequence, frequency, and task order has been configured for all environments (CA7, Local)
Story met acceptance criteria

More information on

Kind regards,

Like Sushma likes this

Hi @Rafael Pinto Sperafico 

Thanks a bunch :)



Hi @Rafael Pinto Sperafico 

I need one suggestion from your end,

In jira post function I have added the below code to achieve the page creation in confluence (using page template) from jira server

import com.atlassian.applinks.api.ApplicationLink
import com.atlassian.applinks.api.ApplicationLinkService
import com.atlassian.applinks.api.application.confluence.ConfluenceApplicationType
import com.atlassian.sal.api.component.ComponentLocator
import groovy.json.JsonBuilder
import groovy.json.JsonSlurper
import groovy.xml.MarkupBuilder
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.jql.parser.JqlQueryParser
import com.atlassian.jira.web.bean.PagerFilter
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.MutableIssue
import groovy.xml.MarkupBuilder

def ApplicationLink getPrimaryConfluenceLink() {
def applicationLinkService = ComponentLocator.getComponent(ApplicationLinkService.class)
final ApplicationLink conflLink = applicationLinkService.getPrimaryApplicationLink(ConfluenceApplicationType.class)
HashSet<String> typecomponentset = new HashSet();
HashSet<String> typeflowset = new HashSet();
def confluenceLink = getPrimaryConfluenceLink()
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
assert confluenceLink // must have a working app link set up
CustomFieldManager customFieldManager = ComponentAccessor.customFieldManager
def issueManager = ComponentAccessor.getIssueManager()
def jqlQueryParser = ComponentAccessor.getComponent(JqlQueryParser)
def searchProvider = ComponentAccessor.getComponent(SearchProvider)
def searchService = ComponentAccessor.getComponent(SearchService)
def user = ComponentAccessor.jiraAuthenticationContext.getLoggedInUser()
HashSet batchset = new HashSet();
def impcomponent = customFieldManager.getCustomFieldObjectByName("Impacted Technical Components")
def impcomponentvalues = issue.getCustomFieldValue(impcomponent)
impcomponentvalues.each { impcomponentvalue ->
Issue issue = impcomponentvalue as MutableIssue
if(issue.getIssueType().name == "Component") {
def typeofcomponent = impcomponentvalue.toString()
MutableIssue childissue = ComponentAccessor.getIssueManager().getIssueObject(typeofcomponent)
def cField = customFieldManager.getCustomFieldObjectByName("Type of Component")
def val = childissue.getCustomFieldValue(cField).toString()
else if(issue.getIssueType().name == "Flow") {
def typeofcomponent = impcomponentvalue.toString()
MutableIssue childissue = ComponentAccessor.getIssueManager().getIssueObject(typeofcomponent)
def cField = customFieldManager.getCustomFieldObjectByName("Type of Flow")
def val = childissue.getCustomFieldValue(cField).toString()
else {"other technical component")
def query = jqlQueryParser.parseQuery("project = DD AND \"Type of Impacted Technical Component\" = Batch")
def search =, query, PagerFilter.getUnlimitedFilter())
search.getIssues().each { documentIssue ->
def dod = issueManager.getIssueObject(
def query1 = jqlQueryParser.parseQuery("project = DD AND \"Type of Impacted Technical Component\" = Interface")
def search1 =, query1, PagerFilter.getUnlimitedFilter())
search1.getIssues().each { documentIssue1 ->
def dod1 = issueManager.getIssueObject(

int count = 0;
batchset.each { e ->

def params = [
title: "${issue.key}" + " : " + "${issue.summary}",    //page title
tamplateid : 12386309 , // template id
key : issue.key ,          //issue key
body : writer.toString()     // batch Dod's

def authenticatedRequestFactory = confluenceLink.createImpersonatingAuthenticatedRequestFactory()
.createRequest(Request.MethodType.POST, "/rest/scriptrunner/latest/custom/createPageFromTitle")
.addHeader("Content-Type", "application/json")
.setRequestBody(new JsonBuilder(params).toString())
.execute(new ResponseHandler<Response>() {
void handle(Response response) throws ResponseException {
if(response.statusCode != HttpURLConnection.HTTP_OK) {
throw new Exception(response.getResponseBodyAsString())
else {
def webUrl = new JsonSlurper().parseText(response.responseBodyAsString)["_links"]["webui"]

In the above code ,I am passing 4 paramters: title template id

3.issue key

4. set of values that needs to be appear in the confluence page as checklist values (which is shown in the below screenshot)


To receive the above parameters I created the REST endpoint in confluence using the below script.

import groovy.transform.BaseScript
import com.atlassian.confluence.spaces.Space
import com.atlassian.confluence.pages.Page
import com.atlassian.confluence.spaces.SpaceManager
import com.atlassian.confluence.pages.PageManager
import com.atlassian.confluence.core.DefaultSaveContext
import com.atlassian.confluence.api.impl.sal.ConfluenceApplicationProperties
import com.atlassian.sal.api.component.ComponentLocator
import com.atlassian.confluence.pages.templates.PageTemplateManager

/*import com.atlassian.confluence.pages.templates.variables.Variable
import com.atlassian.confluence.pages.templates.PageTemplate*/

import javax.servlet.http.HttpServletRequest
import static

@BaseScript CustomEndpointDelegate delegate

import org.apache.log4j.Logger
import org.apache.log4j.Level
def log = Logger.getLogger("com.acme.workflows")

def confluenceApplicationProperties = ComponentLocator.getComponent(ConfluenceApplicationProperties)
httpMethod: "POST") {MultivaluedMap queryParams, String body ->

def mapper = new ObjectMapper()
def params = mapper.readValue(body, Map)
assert params.key
assert params.title
assert params.tamplateid
assert params.body

def pageTemplateManager = ComponentLocator.getComponent(PageTemplateManager)
def spaceManager = ComponentLocator.getComponent(SpaceManager)
def pageManager = ComponentLocator.getComponent(PageManager)
Space space = spaceManager.getSpace("TES")
Page HomePage = space.getHomePage()
def NewParentPage
try {
def pageTemplate = pageTemplateManager.getPageTemplate(params.tamplateid as Long)
String tamplateAsString = pageTemplate.getContent()
String issuekey = params.key
String pageTitle= params.title
NewParentPage = new Page(title: pageTitle, bodyAsString: tamplateAsString, space: space, parentPage: HomePage)
NewParentPage.setBodyAsString(tamplateAsString.replaceAll("batchset","${params.body}")) //here I am setting the body of the confluence page
pageManager.saveContentEntity(NewParentPage, DefaultSaveContext.DEFAULT)
pageManager.saveContentEntity(HomePage, DefaultSaveContext.MINOR_EDIT)
} catch (e) {
return Response.serverError().entity([error: e.message]).build()


My template format is as shown below

template structure.PNGhere what i am doing is I am replacing the "batchset" value with the "body" which is received from Jira.

Using the above code I am successfully able create a page in confluence.

But my concern is ,

If someone adds a new values to the batchset in jira I need to update the page with the newly added values.

So to update the page , I created a button on the confluence page. My requirement is on clicking the "Refresh" button I want to update the existing confluence page with the newly added values .

I am not getting any way to update the page .

Do you have any idea to achieve it ?

Please help me to resolve this bottleneck.

Thanks in advance 

Kind Regards


Hi @Sushma ,

Based on what you have described, perhaps would be best when creating a page in Confluence you get the response from page creation and have it stored in Jira (e.g customField, issueLink). Then, use this information to update the page created wherever changes in a Jira issue happens (it would work as a push notification of some sort to Confluence)

Perhaps, you should consider creating the page you described (e.g Page Created from Jira) in previous comment on a separate location and have Include Page Macro to include this page (Page Created from Jira) in another page where you actually need the info to be displayed and available.

Furthermore, if you update checkbox statuses, you should be pushing those changes to Jira using the Jira Issue you have passed as argument during page creation, so you know which issue the page relates to.

It has been very interesting seeing how this thread developed. For reference, please be aware that Atlassian has the Atlassian Developer Community so instead of posting developing inquires in here, you would be much better assisted by raising development inquires in there instead.

Hope the above helps.

Kind regards;

Suggest an answer

Log in or Sign up to answer
Community showcase
Published in Marketplace Apps & Integrations

Staying organized with Jira: best practices for a better project management

Project managers know this problem: A “mountain of work” lays in front of you, and you don’t know how and where to tackle them. Different to-dos lie ahead, but just one task after the other can be ha...

232 views 2 1
Read article

Community Events

Connect with like-minded Atlassian users at free events near you!

Find an event

Connect with like-minded Atlassian users at free events near you!

Unfortunately there are no Community Events near you at the moment.

Host an event

You're one step closer to meeting fellow Atlassian users at your local event. Learn more about Community Events

Events near you