Storing a paragraph related report

To allow for an in-depth analysis of issues found during a check Congree provides a detail view in the "Reporting". Rather than providing just data that are important to do statistical analyses it is possible to store all the information given in the linguistic check panel.

In Congree's Reporting section a detailed report may look like shown below:


Each item in the list is assigned to the id of the paragraph where the issue was found. It's good practise to use Congree's contexts as the identifier for a paragraph/check unit.

Let's discuss the idea using a sample check. The check request contains the JSON object schown below:

{
  "Xml": "<doc><p>Congratulations on your purrchase of the ContentGrasp SX headset.</p><p> This revolutionary device will significantly improve the quality of your technical documentation without implementing an additional work step. During the normal review, the reviewers or test persons can check</p></doc>",
  "Options": {
    "IncludeValidTerms": true,
    "IncludeReporting": true,
    "IncludeContextMapping": true,
    "ExtractTermCandidates": true
  }
}

The check result is this:

{
  "ResultXml": "<doc><p><?cngr-ctx-b 1?>Congratulations on your <?cngr-lc-b 0?>purrchase<?cngr-lc-e 0?> of the ContentGrasp SX headset.<?cngr-ctx-e 1?></p><p><?cngr-ctx-b 2?> This revolutionary device <?cngr-lc-b 1?><?cngr-lc-b 2?>will<?cngr-lc-e 2?> significantly improve<?cngr-lc-e 1?> the quality of your <?cngr-lc-b 3?>technical documentation<?cngr-lc-e 3?> without implementing an <?cngr-lc-b 4?>additional<?cngr-lc-e 4?> <?cngr-lc-b 5?>work step<?cngr-lc-e 5?>. During the <?cngr-lc-b 6?>normal review<?cngr-lc-e 6?>, the reviewers or <?cngr-lc-b 7?>test persons<?cngr-lc-e 7?> can <?cngr-lc-b 8?><?cngr-lc-b 9?>check<?cngr-lc-e 9?><?cngr-lc-e 8?><?cngr-ctx-e 2?></p></doc>",
  "Errors": [
    {
      "Id": "0",
      "ContextId": 1,
      "Type": "Spelling",
      "Descriptions": [
        {
          "Code": "unknownres",
          "Description": {
            "Header": "Review the spelling of this word.",
            "Instruction": "Correct the word if necessary.",
            "Explanation": "This word is not recognized. Either it is a proper name or it contains a spelling mistake."
          },
          "Explanation": [],
          "ExplanationRewrite": []
        }
      ],
      "Proposals": [
        {
          "Text": "purchase",
          "AdditionalInfo": null,
          "BaseTermForm": null,
          "ConceptId": 0
        }
      ]
    },
    {
      "Id": "1",
      "ContextId": 2,
      "Type": "Style",
      "Descriptions": [
        {
          "Code": "s752en",
          "Description": {
            "Header": "Review the writing style.",
            "Instruction": "Avoid the future tense. Use the present tense if appropriate.",
            "Explanation": "The future tense is not appropriate in technical documentation."
          },
          "Explanation": [
            {
              "Type": "Text",
              "Text": "If you attempt to copy a directory without using this option, you "
            },
            {
              "Type": "Explanation",
              "Text": "will receive"
            },
            {
              "Type": "Text",
              "Text": " an error message."
            }
          ],
          "ExplanationRewrite": [
            {
              "Type": "Text",
              "Text": "If you attempt to copy a directory without using this option, you "
            },
            {
              "Type": "Explanation",
              "Text": "receive"
            },
            {
              "Type": "Text",
              "Text": " an error message."
            }
          ]
        }
      ],
      "Proposals": []
    },
    {
      "Id": "2",
      "ContextId": 2,
      "Type": "Terminology",
      "Descriptions": [
        {
          "Code": "DEPR",
          "Description": {
            "Header": "Review this term.",
            "Instruction": "Replace with the corresponding preferred term.",
            "Explanation": "The status of this term in term database is 'deprecated'."
          },
          "Explanation": [],
          "ExplanationRewrite": []
        }
      ],
      "Proposals": [
        {
          "Text": "can",
          "AdditionalInfo": null,
          "BaseTermForm": "would",
          "ConceptId": 1689
        }
      ]
    },
    {
      "Id": "4",
      "ContextId": 2,
      "Type": "ValidTerm",
      "Descriptions": [],
      "Proposals": [
        {
          "Text": "additional",
          "AdditionalInfo": null,
          "BaseTermForm": "additional",
          "ConceptId": 831
        }
      ]
    },
    {
      "Id": "8",
      "ContextId": 2,
      "Type": "Grammar",
      "Descriptions": [
        {
          "Code": "g523en",
          "Description": {
            "Header": "Review punctuation.",
            "Instruction": "Insert a punctuation mark such as '.', '!', '?', ':' if appropriate.",
            "Explanation": "Sentences end with a punctuation mark."
          },
          "Explanation": [
            {
              "Type": "Text",
              "Text": "Sentences have punctuation marks at the "
            },
            {
              "Type": "Explanation",
              "Text": "end"
            }
          ],
          "ExplanationRewrite": [
            {
              "Type": "Text",
              "Text": "Sentences have punctuation marks at the "
            },
            {
              "Type": "Explanation",
              "Text": "end."
            }
          ]
        }
      ],
      "Proposals": []
    },
    {
      "Id": "9",
      "ContextId": 2,
      "Type": "Terminology",
      "Descriptions": [
        {
          "Code": "ADM",
          "Description": {
            "Header": "Review this term.",
            "Instruction": "Check whether it is better to use the corresponding preferred term.",
            "Explanation": "The status of this term in term database is 'admitted'."
          },
          "Explanation": [],
          "ExplanationRewrite": []
        }
      ],
      "Proposals": [
        {
          "Text": "select",
          "AdditionalInfo": null,
          "BaseTermForm": "check",
          "ConceptId": 927
        }
      ]
    }
  ],
  "TermCandidates": [
    {
      "Id": "3",
      "Text": "technical documentation",
      "Context": " This revolutionary device will significantly improve the quality of your technical documentation without implementing an additional work step. During the normal review, the reviewers or test persons can check",
      "IsExist": false
    },
    {
      "Id": "5",
      "Text": "work step",
      "Context": " This revolutionary device will significantly improve the quality of your technical documentation without implementing an additional work step. During the normal review, the reviewers or test persons can check",
      "IsExist": false
    },
    {
      "Id": "6",
      "Text": "normal review",
      "Context": " This revolutionary device will significantly improve the quality of your technical documentation without implementing an additional work step. During the normal review, the reviewers or test persons can check",
      "IsExist": false
    },
    {
      "Id": "7",
      "Text": "test person",
      "Context": " This revolutionary device will significantly improve the quality of your technical documentation without implementing an additional work step. During the normal review, the reviewers or test persons can check",
      "IsExist": false
    }
  ],
  "Reporting": {
    "TotalCheckedWords": 46,
    "ReleaseLevel": 23.91,
    "RelativeReleaseLevel": 11.251764705882353,
    "SafeReleaseLevel": 95.0,
    "SafeReleaseLevelTitle": "Excellent",
    "AcceptableReleaseLevel": 85.0,
    "AcceptableReleaseLevelTitle": "Acceptable",
    "UnsafeReleaseLevel": 0.0,
    "UnsafeReleaseLevelTitle": "Unacceptable",
    "ReportingByTypes": [
      {
        "Type": "Abbreviation",
        "ErrorCount": 0,
        "Severity": 100.0,
        "RelativeSeverity": 120.0
      },
      {
        "Type": "Grammar",
        "ErrorCount": 1,
        "Severity": 95.65,
        "RelativeSeverity": 85.200000000000045
      },
      {
        "Type": "Spelling",
        "ErrorCount": 1,
        "Severity": 78.26,
        "RelativeSeverity": 36.828235294117647
      },
      {
        "Type": "Style",
        "ErrorCount": 1,
        "Severity": 97.83,
        "RelativeSeverity": 102.63999999999999
      },
      {
        "Type": "Terminology",
        "ErrorCount": 2,
        "Severity": 52.17,
        "RelativeSeverity": 24.550588235294121
      },
      {
        "Type": "ValidTerm",
        "ErrorCount": 1,
        "Severity": 100.0,
        "RelativeSeverity": 120.0
      }
    ]
  },
  "FailedParagraphsInfo": {
    "FailedParagraphsAmount": 0
  }
}

In the property "ResultXml" we see that we have two contexts marked by the processing instructions <?cngr-ctx-b 1?> (begin of context 1), <?cngr-ctx-e 1?> (end of context 1), <?cngr-ctx-b 2?> (begin of context 2) and <?cngr-ctx-b 2?> (end of context 2). We will be using the numbers of the contexts as the id of the paragraphs.

To store the paragrah related information we will be iterating through the contexts and the errors belonging to the context.

The first step is to get the number of contexts. The method shown below is one possible way.

 private static int GetContextsNumber(CongreeCheckresult result)
        {

            MatchCollection matches = Regex.Matches(result.ResultXml, "(cngr-ctx-b)");
            
            return matches.Count;
        }

The parameter of type CongreeCheckresult is desribed here: Processing the check result

The second step is to iterate all contexts, find all errors within the current context, create a paragraph report and store it.

To get all errors belonging to the actual context the next method might be helpful.

 private static List<Congree.Error> GetErrorByContext(int num, CongreeCheckresult result)
        {

            List<Congree.Error> errorList = new List<Congree.Error>();

            foreach(Congree.Error error in result.Errors)
            {
                if(error.ContextId == num.ToString())
                {
                    errorList.Add(error);
                }
            }

            return errorList;
        }


The complete content of the context can be obtained using the following method.

 private static string GetContext(int num, CongreeCheckresult result)
        {

            string pattern = @"<\?cngr-ctx-b " + num + @"\?>(.+)<\?cngr-ctx-e " + num + @"\?>";

            MatchCollection matches = Regex.Matches(result.ResultXml, pattern);
            if (matches.Count > 0) {
                return matches[0].Value;
            }
            return "";
        }


The method to store a paragraph related report is shown below:

public void StoreParagraphReport(string sessionid, string paragraphid, CongreeRestApiSample.Reporting.Congree.ParagraphReport message)
        {
            var client = new RestClient(this.serverUrl + "/congree/api/Linguistic/Reporting/v1/Sessions/" + sessionid + "/Paragraphs/" + paragraphid);
            var request = new RestRequest(Method.PUT);
            request.AddHeader("Content-Type", "application/json");
            request.AddHeader("Authorization", "Bearer " + this.token);
            var jsonmessage = JsonConvert.SerializeObject(message);
            request.AddParameter("undefined", jsonmessage, ParameterType.RequestBody);
            IRestResponse response = client.Execute(request);
        }


The parameter message is an object of the class ParagraphReport shown below.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CongreeRestApiSample.Reporting.Congree
{
    public class Error
        
    {
        public int ErrorId { get; set; }
        public string ErrorType { get; set; }
        public string ErrorCode { get; set; }
        public string Notification { get; set; }
        public List<string> Proposals { get; set; }
        public string Status { get; set; }
    }

    public class ParagraphReport
    {
        public List<Error> Errors { get; set; }
        public string Context { get; set; }
    }
}


If the document check yields no errors pass for each paragraph/context as request with the context only, i.e. the Errors arry is empty. If the context is an empty string, don't store it.


Property in Paragraph ReportProperty in CongreeCheckResult
ErrorIdId in Errors
ErrorTypeType in Errors
ErrorCodeCode in Errors
NotificationHeader in Descriptions/Description
ProposalsAn array containing the strings in Text in each Proposal
StatusThe information on the status, e.g. how the user dealt with the issue. Possible values are "Normal", "Ignored", "Disregarded"