Hi,
Does anyone have any idea how can we get descriptions and comments as plain text in issues?
Thanks
Hi,
Does anyone have any idea how can we get descriptions and comments as plain text in issues?
Thanks
Hi @HarshModhiya,
Have you tried version 2 Get issue REST API?
GET /rest/api/2/issue/{issueKeyOrId}?fields=comment,description
If this does not suit your needs, can you share the API you are currently using as well as the response format you are looking for?
Cheers,
Ian
Hi @ianRagudo ,
I am using /rest/agile/1.0/board/{boardid}/issue
API and got comment and description in ADF format but I want only plain text without any formatting.
Thanks,
Harsh
Hi @HarshModhiya ,
You can extract plain text from ADF by mapping through it and looking at all nodes marked text
. For an example on how to do that, see: Is it posible to get the body comment as plain text - #16 by AveryLane
Hi @mventnor ,
Thanks for your quick suggestion.
As I can see this is a scripting method. Do we have any method available for C#?
Thanks,
Harsh
Hi @HarshModhiya,
I am the one that originally wrote the script that @mventnor linked to. Here is an example in .NET 5.0 that uses the Newtonsoft.Json package (v13.03) to parse the JSON then extract all of the text nodes.
using System;
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
class Program
{
static void Main(string[] args)
{
string jsonString = @"
{
""version"": 1,
""type"": ""doc"",
""content"": [
{
""type"": ""heading"",
""attrs"": {
""level"": 1
},
""content"": [
{
""type"": ""text"",
""text"": ""Lorem""
}
]
},
{
""type"": ""paragraph"",
""content"": [
{
""type"": ""text"",
""text"": ""Lorem ""
},
{
""type"": ""text"",
""text"": ""ipsum"",
""marks"": [
{
""type"": ""strong""
}
]
},
{
""type"": ""text"",
""text"": "" dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris ""
},
{
""type"": ""text"",
""text"": ""nisi ut aliquip ex ea commodo"",
""marks"": [
{
""type"": ""em""
},
{
""type"": ""underline""
}
]
},
{
""type"": ""text"",
""text"": "" consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. ""
}
]
},
{
""type"": ""paragraph"",
""content"": [
{
""type"": ""text"",
""text"": ""Excepteur sint occaecat cupidatat non proident, ""
},
{
""type"": ""text"",
""text"": ""sunt in culpa qui officia"",
""marks"": [
{
""type"": ""em""
}
]
},
{
""type"": ""text"",
""text"": "" deserunt mollit anim id est laborum.""
}
]
},
{
""type"": ""bulletList"",
""content"": [
{
""type"": ""listItem"",
""content"": [
{
""type"": ""paragraph"",
""content"": [
{
""type"": ""text"",
""text"": ""Sed ""
}
]
}
]
},
{
""type"": ""listItem"",
""content"": [
{
""type"": ""paragraph"",
""content"": [
{
""type"": ""text"",
""text"": ""ut ""
},
{
""type"": ""text"",
""text"": ""unde"",
""marks"": [
{
""type"": ""strong""
},
{
""type"": ""textColor"",
""attrs"": {
""color"": ""#bf2600""
}
}
]
}
]
}
]
},
{
""type"": ""listItem"",
""content"": [
{
""type"": ""paragraph"",
""content"": [
{
""type"": ""text"",
""text"": ""perspiciatis ""
}
]
}
]
}
]
},
{
""type"": ""paragraph"",
""content"": []
},
{
""type"": ""paragraph"",
""content"": []
}
]
}";
// Parse the JSON string
JObject jsonObject = JObject.Parse(jsonString);
// Extract the text nodes recursively
List<string> textNodes = ExtractTextNodes(jsonObject);
// Print the text nodes to the console
foreach (string textNode in textNodes)
{
Console.WriteLine(textNode);
}
}
static List<string> ExtractTextNodes(JToken token)
{
List<string> textNodes = new List<string>();
if (token.Type == JTokenType.Object)
{
foreach (JProperty property in token.Children<JProperty>())
{
textNodes.AddRange(ExtractTextNodes(property.Value));
}
}
else if (token.Type == JTokenType.Array)
{
foreach (JToken value in token.Children())
{
textNodes.AddRange(ExtractTextNodes(value));
}
}
else if (token.Type == JTokenType.Property)
{
JProperty property = (JProperty)token;
textNodes.AddRange(ExtractTextNodes(property.Value));
}
else if (token.Type == JTokenType.String && token.Parent != null && token.Parent.Type == JTokenType.Property && ((JProperty)token.Parent).Name == "text")
{
textNodes.Add(token.ToString());
}
return textNodes;
}
}
Here is the output that is produced:
Lorem
Lorem
ipsum
dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident,
sunt in culpa qui officia
deserunt mollit anim id est laborum.
Sed
ut
unde
perspiciatis
Here is a brief explanation of the program:
jsonString
string is parsed into a JObject
using the JObject.Parse
method. This creates an in-memory representation of the JSON document that we can manipulate and query in the rest of the program.ExtractTextNodes
method is called, passing the parsed JObject
as a parameter. This method is defined to recursively traverse the JSON structure and collect all “text” node values into a List<string>
.This method uses pattern matching on the type of each JToken
it encounters during its traversal:JObject
(i.e., a JSON object), it extracts all of its properties and recursively calls ExtractTextNodes
on each property’s value.JArray
(i.e., a JSON array), it recursively calls ExtractTextNodes
on each of its children.JProperty
(i.e., a JSON key-value pair), it recursively calls ExtractTextNodes
on the property’s value.JValue
of type string and its parent is a JProperty
with the name “text”, it adds the string value of the token to the list of text nodes. This is the base case for the recursion, meaning the point at which it stops calling itself and starts returning results.I am not as familiar with C# so this wasn’t as thoroughly tested as the original Javascript that I wrote but hopefully it is enough of a starting point for you to write your own class definition in C# to suite your specific needs.