Update an Answer Set Programmatically
API Version: v2.0
Method: GET and PUT
Endpoint: /WorkItems/{workItemId}/AnswerSet/Content
You can update an answer set externally, and then return it to Advance using an API call. This is useful if you have external data you wish to add, for example a reference number from a third-party application.
Overview
When data is added to a work item, Advance saves this in the form of HotDocs Answer XML. Typically new information is added to an answer set through an interview with a user, but it is also possible to update an answer set externally and return this data to HotDocs.
Take care when sending HotDocs Answer XML to a work item that has existing work item versions. When you begin an assembly session and attach new Answer XML, HotDocs replaces the existing Answer XML file with the new file. If there are existing answers which you wish to retain, ensure you keep them in the replacement answer file.
Workflow
You first query a work item version for the Answer XML you wish to update. Then you can edit or update the answer set in your own applications or processes. To return the updated answer set to Advance, you use the create new work item version API method to create a new assembly session for a work item, attaching your answer data as HotDocs Answer XML.
Validating the HotDocs Answer Set XML
When sending HotDocs answer set XML, you must first validate the answer set against the HotDocs answer Set schema.
To retrieve and update existing answer sets
To return an existing answer set for a work item, you use the following endpoint:
- GET /WorkItems/{workItemId}/AnswerSet/Content — returns the answer set in either HotDocs Answer XML or JSON format.
To update an answer set in this way, choose the HotDocs Answer XML format.
You can now edit or update the answer set as needed. Be sure to keep any answers you wish to retain.
Once you are happy with your answer set, you can call the following endpoint, attaching your Answer XML in the body of the request, to update the work item version.
- PUT /WorkItems/{workItemId}/AnswerSet/Content
There are additional considerations if you are updating image values in your answer set.
Code Example
using System.Text;
using System.Text.Json;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Schema;
namespace HotDocsAdvance.Help.CodeExamples.AnswerSets;
// Code assumes a valid token has been obtained.
/// <summary>
/// This class provides a code example to use the HotDocs Advance API 2.0 answer set update endpoint.
/// </summary>
/// <remarks>
/// The relevant endpoint is a PATCH found on the swagger documentation under the workitem section,
/// and the answerSet sub resource.
/// </remarks>
/// <param name="httpClient"> Standard framework HttpClient. </param>
/// <param name="baseAdvanceApiUrl"> Base URL for your environment and tenancy's HD Advance API. No version required.
/// E.g. For a swagger documentation found on https://sometenancy.mycompanydomain.com/api/rest/documentation/index.html
/// The base url would be: https://tenancy.yourorganization.com/api
/// </param>
/// <param name="token"> A working HD Advance API access token. See the relevant documentation as to how to get a token.</param>
/// <param name="xsdStrings"> A collection of key (xml namespace) and value (xml schema (XSD) as strings) pairs to use
/// while validating the answers. </param>
public class UpdateAnswerSetCodeExample(
HttpClient httpClient,
string baseAdvanceApiUrl,
string token,
ICollection<KeyValuePair<string, string>> xsdStrings)
{
// These two lines define XML namespaces to be reused across the code.
private static readonly XNamespace hd = "http://www.hotdocs.com/schemas/answer_set/2017";
private static readonly XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
/// <summary>
/// This is a placeholder class, that serves a purpose only for this code example. It is meant to contain and expose
/// result of the operation when successful.
/// </summary>
public class PatchAnswerSetResponse
{
public ICollection<string> UnresolvedImageReferences { get; set; } = [];
}
public async Task<PatchAnswerSetResponse?> UpdateAnswerSetAsync(Guid workItemId)
{
// Creates the full URI for HD Advance API 2.0 AnswerSet PATCH, endpoint (overlay).
// Please note the correct usage of forward slashes, or utilize another method to construct the full patch URI.
var patchAnswersUri = new Uri(new Uri(baseAdvanceApiUrl),
$"rest/v2/WorkItems/{workItemId}/AnswerSet/Content");
var constructedAnswerXml = PrepareNewAnswerSet();
if(!ValidateAgainstSchemas(new XDocument(constructedAnswerXml)))
{
throw new InvalidOperationException("The answer set is not valid.");
}
// Constructs the request message, with the provided answer XML as content and the relevant access token.
using var requestContent =
new StringContent(constructedAnswerXml.ToString(), Encoding.UTF8, "application/xml");
using var requestMessage = new HttpRequestMessage(HttpMethod.Patch, patchAnswersUri);
requestMessage.Headers.Add("Authorization", $"Bearer {token}");
requestMessage.Content = requestContent;
// Executes the requests, enforces a successful response (HTTP status 2xx),
// and returns the response content parsed in the appropriate format.
var response = await httpClient.SendAsync(requestMessage);
response.EnsureSuccessStatusCode(); // Handle relevant error scenarios accordingly. E.g. Http Codes: 401, 403, 404, 409, etc.
return JsonSerializer.Deserialize<PatchAnswerSetResponse>(await response.Content.ReadAsStringAsync());
}
private static XElement PrepareNewAnswerSet()
{
// The root element of an HD answer set, including the namespace.
var root = new XElement(hd + "answerSet");
// Adding the namespaces for compatibility.
root.Add(new XAttribute(XNamespace.Xmlns + "xsi", "http://www.w3.org/2001/XMLSchema-instance"));
root.Add(new XAttribute(XNamespace.Xmlns + "hd", "http://www.hotdocs.com/schemas/answer_set/2017"));
// Adding standard HD answer set attributes.
root.Add(new XAttribute("version", "2.0"));
root.Add(new XAttribute("title", ""));
// Adding the answers themselves.
root.Add(GetTextAnswerWithValue("FirstName", null));
root.Add(GetTextAnswerWithValue("LastName", "Thomson"));
root.Add(GetTextAnswerWithValue("FamilyName", "Rodriguez"));
return root;
}
private static XElement GetTextAnswerWithValue(string variableName, string? value)
{
// This method creates an answer with the correct namespaces, values and variable names.
var answer = new XElement(hd + "textAnswer", new XAttribute("name", variableName));
answer.Add(value is null
? new XElement(hd + "value", new XAttribute(xsi + "nil", true))
: new XElement(hd + "value", value));
return answer;
}
private bool ValidateAgainstSchemas(XDocument answersXml)
{
bool isXmlValid = true;
var schemaSet = new XmlSchemaSet();
foreach ((string targetNamespace, string xsd) in xsdStrings)
{
schemaSet.Add(targetNamespace, XmlReader.Create(new StringReader(xsd)));
}
answersXml.Validate(schemaSet, (o, e) => { isXmlValid = false; });
return isXmlValid;
}
}
Next Steps