FHIR Chat · Using liquid · IG creation

Stream: IG creation

Topic: Using liquid


view this post on Zulip Grahame Grieve (Apr 14 2020 at 06:22):

@Keith Boone asked for more documentation about how to use liquid. So here goes:

view this post on Zulip Grahame Grieve (Apr 14 2020 at 06:23):

in your IG you define a parameter path-liquid that points to a directory where you have liquid templates. E.g. path-liquid=liquid

view this post on Zulip Grahame Grieve (Apr 14 2020 at 06:24):

then, in that directory, you have a series of files like Patient.liquid - .e.g with the name of the resource that they are the template for

view this post on Zulip Grahame Grieve (Apr 14 2020 at 06:25):

the liquid template will be executed automatically when generating the narrative for any resource of that type.

view this post on Zulip Grahame Grieve (Apr 14 2020 at 06:25):

the liquid spec is found here: https://confluence.hl7.org/display/FHIR/FHIR+Liquid+Profile

view this post on Zulip Grahame Grieve (Apr 14 2020 at 06:25):

here's an example:

view this post on Zulip Grahame Grieve (Apr 14 2020 at 06:34):

<div xmlns="http://www.w3.org/1999/xhtml">
  <table>
  <tbody>
   <tr>
    <td> Name</td>
    <td>
{%loop name in Patient.name%}
 <b>{{name.family}}</b>, {{name.given}} </br>
{%endloop%}
    </td>
  </tr>
  <tr>
    <td> Address</td>
    <td>{{Patient.address.text}}</td>
  </tr>
  <tr>
    <td> Contacts</td>
    <td> Home: unknown. Work: (03) 5555 6473</td>
  </tr>
  {%if Patient.identifier.exists()%}
  <tr>
    <td> Id</td>
    <td> {{identifier[0].type.text}}: {{identifier[0].value}}</td>
  </tr>
  {%endif%}
  </tbody>
  </table>
</div>

view this post on Zulip Grahame Grieve (Apr 14 2020 at 06:38):

there's a rather useful FHIRPath function defined in the IG publisher called .render() which applies to data types which takes a lot of the finickity work out of this - you can use it on any data type, and it will generate the text that it think best represents the data type

view this post on Zulip Grahame Grieve (Apr 14 2020 at 06:39):

e.g. the fragment above, you want to render and address... well, you can write liquid for all the possible combinations of Address... you can just do .render() and let my code do it.. and mostly my code is pretty robust

view this post on Zulip Grahame Grieve (Apr 14 2020 at 06:40):

Keith - let me know if you want more... and it would be lovely if someone turned this into doco somewhere,,,?

view this post on Zulip Jose Costa Teixeira (Apr 14 2020 at 07:47):

Somewhere = the guidance IG?

view this post on Zulip Grahame Grieve (Apr 14 2020 at 09:59):

probably confluence for thta

view this post on Zulip Grahame Grieve (Apr 14 2020 at 09:59):

though an example in the guidance IG would also be excellent

view this post on Zulip Eric Haas (Jun 04 2020 at 21:13):

@Grahame Grieve will .render() work for references and url so that you get a link? It currently causes an error when I try to use it like so...

<ul>
{% for var in Subscription.modifierExtension %}
<li>(<strong>url:</strong> {{var.url.render()}}, <strong>value: </strong>{{var.valueUri.render()}})</li>
{% endfor %}
</ul>

view this post on Zulip Eric Haas (Jun 04 2020 at 21:14):

there is a " not yet implemented error" error

view this post on Zulip Grahame Grieve (Jun 04 2020 at 21:19):

have you got a full stack?

view this post on Zulip Eric Haas (Jun 04 2020 at 21:30):

Load Content                                                                     (00:56.0332)
Processing Conformance Resources                                                 (00:56.0852)
Publishing Content Failed: Not done yet (IGPublisherHostServices.resolveFunction) (00:58.0736)
                                                                                 (00:58.0737)
Use -? to get command line help                                                  (00:58.0737)
                                                                                 (00:58.0737)
Stack Dump (for debugging):                                                      (00:58.0738)
org.apache.commons.lang3.NotImplementedException: Not done yet (IGPublisherHostServices.resolveFunction)
    at org.hl7.fhir.igtools.publisher.Publisher$IGPublisherHostServices.resolveFunction(Publisher.java:377)
    at org.hl7.fhir.r5.utils.LiquidEngine.resolveFunction(LiquidEngine.java:623)
    at org.hl7.fhir.r5.utils.FHIRPathEngine.parseExpression(FHIRPathEngine.java:902)
    at org.hl7.fhir.r5.utils.FHIRPathEngine.parseExpression(FHIRPathEngine.java:938)
    at org.hl7.fhir.r5.utils.FHIRPathEngine.parseExpression(FHIRPathEngine.java:938)
    at org.hl7.fhir.r5.utils.FHIRPathEngine.parse(FHIRPathEngine.java:369)
    at org.hl7.fhir.r5.utils.FHIRPathEngine.parse(FHIRPathEngine.java:362)
    at org.hl7.fhir.r5.utils.LiquidEngine$LiquidStatement.evaluate(LiquidEngine.java:141)
    at org.hl7.fhir.r5.utils.LiquidEngine$LiquidFor.evaluate(LiquidEngine.java:268)
    at org.hl7.fhir.r5.utils.LiquidEngine.evaluate(LiquidEngine.java:102)
    at org.hl7.fhir.r5.renderers.LiquidRenderer.render(LiquidRenderer.java:65)
    at org.hl7.fhir.r5.renderers.ResourceRenderer.render(ResourceRenderer.java:76)
    at org.hl7.fhir.igtools.publisher.Publisher.generateNarratives(Publisher.java:1032)
    at org.hl7.fhir.igtools.publisher.Publisher.loadConformance(Publisher.java:3605)
    at org.hl7.fhir.igtools.publisher.Publisher.createIg(Publisher.java:834)
    at org.hl7.fhir.igtools.publisher.Publisher.execute(Publisher.java:696)
    at org.hl7.fhir.igtools.publisher.Publisher.main(Publisher.java:7430)
(venv37) Erics-MacBook-Air-2:subscription-backport-ig ehaas$

view this post on Zulip Eric Haas (Jun 04 2020 at 21:31):

it could be user error or misuse. i am not sure what it would do for a url.

view this post on Zulip Eric Haas (Jun 05 2020 at 02:50):

I got this to work on Patient and Subscription but not on Bundle. Is there a reason why can't use on Bundles?

view this post on Zulip Eric Haas (Jun 05 2020 at 02:53):

@Grahame Grieve ?

view this post on Zulip Grahame Grieve (Jun 05 2020 at 03:25):

narrative generation won't work for bundles since they don't have narrative

view this post on Zulip Eric Haas (Jun 05 2020 at 18:44):

Ah stupid me...the Ig publisher is generating a display for them nonetheless, is that a template used by the publisher and can that be customized?

view this post on Zulip Grahame Grieve (Jun 05 2020 at 20:48):

to some degree - some bundles are rendered differently, but other than the special cases, the rendering is a series of html fragments separated by <hr/>, and where the default renderer is used for each entry. So liquid would apply

view this post on Zulip Jose Costa Teixeira (Feb 20 2021 at 16:40):

I need to use this to render PlanDefinitions, but only a specific profile of PlanDefinitions.

view this post on Zulip Jose Costa Teixeira (Feb 20 2021 at 16:43):

Is this a big change to ask?

view this post on Zulip Jose Costa Teixeira (Feb 23 2021 at 22:19):

@Grahame Grieve the reason for me to ask this is:
I want to render some resources using some liquid templates. For this, I need to tell the publisher:

  • resource type A, profile 1 - liquid template X
  • resource type A, profile 2 - liquid template Y
  • resource type B, profile 1 - liquid template Z
    For this I need to tell the template what to do for each. Currently I'd have to do a big IF THEN ELSE.

view this post on Zulip Jose Costa Teixeira (Feb 23 2021 at 22:19):

Some of these resources are expected to be custom resources, so i need to differentiate the flavours

view this post on Zulip Grahame Grieve (Feb 24 2021 at 03:23):

at the moment you can't have different liquid templates for different profiles

view this post on Zulip Jose Costa Teixeira (Feb 24 2021 at 05:48):

Is that something we could expose? Or too much work?

view this post on Zulip Grahame Grieve (Feb 24 2021 at 06:03):

I don't know. I haven't really thought about it

view this post on Zulip Jose Costa Teixeira (Feb 24 2021 at 06:38):

If in my liquid folder I have not only plandefinition.liquid but also plandefinition-homecare.liquid and plandefinition-medicationtreatment.liquid and if the publisher would know the difference (i.e. homecareand medicationtreatment are the profile ids) that would be helpful

view this post on Zulip Richard Townley-O'Neill (Feb 25 2021 at 04:57):

Is there a way to discover which liquid variables are defined in an IG?
I have found https://confluence.hl7.org/display/FHIR/FHIR+Liquid+Profile but values like {{ page.title }} are not mentioned.

view this post on Zulip Grahame Grieve (Feb 25 2021 at 04:58):

you can read the jekyll documentation ,and look in the _data directory

view this post on Zulip Grahame Grieve (Feb 25 2021 at 04:58):

because that's what jekyll gets access too,

view this post on Zulip Grahame Grieve (Feb 25 2021 at 04:58):

if that's what you mean by liquid.

view this post on Zulip Richard Townley-O'Neill (Feb 25 2021 at 05:01):

Thanks
I found some stuff in temp\pages\_data
Where is the FHIR IG docco?

view this post on Zulip Grahame Grieve (Feb 25 2021 at 05:13):

actually, I'm not sure what you're asking about. there's 2 different contexts in which liquid is used - in jekyll, when building an IG, and in the IG publisher, when creating resource narratives. The work differnetly

view this post on Zulip Richard Townley-O'Neill (Feb 25 2021 at 05:14):

Thanks. I did not know that. I'm looking at variable for creating resource narratives.

view this post on Zulip Richard Townley-O'Neill (Feb 25 2021 at 05:15):

I'm after a variable for the title of a resource. I've found one for the name, but I want to put the title in documentation.

view this post on Zulip Richard Townley-O'Neill (Feb 25 2021 at 05:16):

I thought it would be easy. Now it is a rabbit hole. :smile:

view this post on Zulip Richard Townley-O'Neill (Feb 25 2021 at 05:18):

I can get the name from {{ site.data.structuredefinitions.<RESOURCE ID>.name }}, but there is no title.
I'll do it with text instead of a variable.

view this post on Zulip Jose Costa Teixeira (Feb 25 2021 at 05:21):

@Richard Townley-O'Neill I'm in the rabbit hole (it's nice and cozy and it's dangerous out there). What do you need?

view this post on Zulip Richard Townley-O'Neill (Feb 25 2021 at 05:41):

We have an IG not using the template approach built using the ig.json approach.
On -intro pages for profiles we put the title of the profile at the start. I thought it would be nice to use a variable instead of remembering to change it when the resource gets a new title during development. I found a variable for the ig's title : {{ site.data.fhir.ig.title }}
but for the resource all I could find was a name: {{ site.data.structuredefinitions.<RESOURCE ID>.name }}

I expect there is no such vartiable.

view this post on Zulip Jose Costa Teixeira (Feb 25 2021 at 05:44):

what about site.data.pages?

view this post on Zulip Jose Costa Teixeira (Feb 25 2021 at 05:45):

if you have a pages.json file, does it contain the info?

view this post on Zulip Jose Costa Teixeira (Feb 25 2021 at 05:46):

also site.data.resources should have that info

view this post on Zulip Richard Townley-O'Neill (Feb 25 2021 at 05:50):

pages.json has almost nothing. It has what is in ImplementationGuide.definition.page, and that is just a stub.

view this post on Zulip Grahame Grieve (Feb 25 2021 at 06:02):

if you're generating narrative, you only have what's in the resource that is being generated. If theres's no title in the resource, you can't use it when generating narrative

view this post on Zulip Richard Townley-O'Neill (Feb 25 2021 at 06:05):

The structure definition has a title, which I can see in site.data.resources
With site.data.resources I tried {{ site.data.resources.StructureDefinition/sra-match-record.title}}
and got nothing.
Maybe I need to escape the "/".

view this post on Zulip Grahame Grieve (Feb 25 2021 at 06:11):

I think you're confused. Are you writing liquid for jekyll to process, or for generating narrative?

view this post on Zulip Grahame Grieve (Feb 25 2021 at 06:12):

but if you're writing for a structure definition, the liquid will (or should) never be called - the IG publisher renders that itself

view this post on Zulip Richard Townley-O'Neill (Feb 25 2021 at 06:21):

I am writing for the narrative. I want the circled bit to be a variable
image.png
from https://sra.digitalhealth.gov.au/fhir/currentdraft/StructureDefinition-sra-organization.html

view this post on Zulip Richard Townley-O'Neill (Feb 25 2021 at 06:21):

Gotta go.

view this post on Zulip Grahame Grieve (Feb 25 2021 at 06:38):

there's no variables - you just have access to what's in the resource

view this post on Zulip Max Masnick (Feb 25 2021 at 12:46):

If anyone is trying to get this to work in a SUSHI project, this worked for me:

1) Add the following to sushi-config.yaml:

parameters:
  "liquid-path": "liquid"

2) Create a folder input/liquid/ and add a file like Patient.liquid as Grahame describes above

view this post on Zulip Max Masnick (Feb 25 2021 at 12:47):

When I add my own Patient.liquid file, is there a place I can see the template I'm overriding?

view this post on Zulip Jose Costa Teixeira (Feb 25 2021 at 12:55):

I believe that when you add a Patient.liquid, you are not overriding the template, you are telling the Java code to let it go

view this post on Zulip Max Masnick (Feb 25 2021 at 13:00):

Ah ok, that makes sense

view this post on Zulip Max Masnick (Feb 25 2021 at 13:07):

I have yet to find an object that render() actually works on. For example, Observation.value.render(), Observation.value.coding.render(), Observation.value.coding.code.render() all produce the following exception:

org.apache.commons.lang3.NotImplementedException: Not done yet (IGPublisherHostServices.resolveFunction)
    at org.hl7.fhir.igtools.publisher.Publisher$IGPublisherHostServices.resolveFunction(Publisher.java:385)
    at org.hl7.fhir.r5.utils.LiquidEngine.resolveFunction(LiquidEngine.java:623)
    at org.hl7.fhir.r5.utils.FHIRPathEngine.parseExpression(FHIRPathEngine.java:1038)
    at org.hl7.fhir.r5.utils.FHIRPathEngine.parseExpression(FHIRPathEngine.java:1079)
    at org.hl7.fhir.r5.utils.FHIRPathEngine.parseExpression(FHIRPathEngine.java:1079)
    at org.hl7.fhir.r5.utils.FHIRPathEngine.parse(FHIRPathEngine.java:431)
    at org.hl7.fhir.r5.utils.FHIRPathEngine.parse(FHIRPathEngine.java:423)
    at org.hl7.fhir.r5.utils.LiquidEngine$LiquidStatement.evaluate(LiquidEngine.java:141)
    at org.hl7.fhir.r5.utils.LiquidEngine.evaluate(LiquidEngine.java:102)
    at org.hl7.fhir.r5.renderers.LiquidRenderer.render(LiquidRenderer.java:75)
    at org.hl7.fhir.r5.renderers.ResourceRenderer.render(ResourceRenderer.java:84)
    at org.hl7.fhir.igtools.publisher.Publisher.generateNarratives(Publisher.java:1152)
    at org.hl7.fhir.igtools.publisher.Publisher.loadConformance(Publisher.java:3826)
    at org.hl7.fhir.igtools.publisher.Publisher.createIg(Publisher.java:877)
    at org.hl7.fhir.igtools.publisher.Publisher.execute(Publisher.java:732)
    at org.hl7.fhir.igtools.publisher.Publisher.main(Publisher.java:8417)

Is this truly not implemented, or am I just doing something silly?

view this post on Zulip Grahame Grieve (Feb 25 2021 at 17:45):

truly not implemented.

view this post on Zulip Grahame Grieve (Feb 25 2021 at 17:45):

apparently I overlooked hooking something up

view this post on Zulip Max Masnick (Feb 25 2021 at 17:49):

Well having briefly attempted to replicate the behavior of render() in Liquid, I can definitely see the value of render() :grinning:

view this post on Zulip Grahame Grieve (Feb 25 2021 at 17:49):

y.

view this post on Zulip Grahame Grieve (Feb 25 2021 at 17:50):

it's now on my list

view this post on Zulip Max Masnick (Feb 25 2021 at 17:50):

Thanks!!

view this post on Zulip Brian Kaney (Feb 17 2022 at 23:32):

I have a similar setup and having problems with include.

I would like to create a partial and include it in Patient.liquid. However any attempt at {% include 'test' %} fails in the rendered output with an inline error

Exception generating Narrative: Script template: Error reading include: "test"

I think it is happening here https://github.com/hapifhir/org.hl7.fhir.core/blob/master/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/LiquidEngine.java#L494-L521, but really can't make any sense of what that code is doing.

Any suggestions? Is there an example somewhere of a successful include?

view this post on Zulip Bryn Rhodes (Feb 21 2022 at 19:40):

There is this testcase in the fhir-test-cases repository: https://github.com/FHIR/fhir-test-cases/blob/master/r5/liquid/liquid-tests.json#L46

view this post on Zulip Bryn Rhodes (Feb 21 2022 at 22:13):

It looks like the LiquidEngine that is being used at that point for the narrative generation doesn't have an implementation of the IncludeResolver, so it doesn't know how to get the templates. I've sketched what I _think_ will work here:

view this post on Zulip Bryn Rhodes (Feb 21 2022 at 22:13):

https://github.com/cqframework/org.hl7.fhir.core/pull/2

view this post on Zulip Bryn Rhodes (Feb 21 2022 at 22:14):

But it's a change down in core to the LiquidRenderer

view this post on Zulip Bryn Rhodes (Feb 21 2022 at 22:15):

But I can't get a good build locally due to some seemingly unrelated package cache tests failing

view this post on Zulip Grahame Grieve (Feb 23 2022 at 23:58):

@Bryn Rhodes I don't understand this - the test passes?

view this post on Zulip Bryn Rhodes (Feb 24 2022 at 00:31):

It does, but that's because it sets a includeTemplateResolver in the test setup. When the Liquid Engine is used in the publisher to generate the narratives, it doesn't have an includeTemplateResolver set. We can see in the debug that the templates are loaded in the template provider, but there's no glue from the LiquidEngine to be able to resolve the templates there. So that's what this proposed PR does, just adds a class that implements the template resolver interface using the template provider in the context, and sets the LiquidEngine's include resolver to that instance.

view this post on Zulip Grahame Grieve (Feb 24 2022 at 00:41):

ok well make it as a PR then

view this post on Zulip Bryn Rhodes (Feb 24 2022 at 02:57):

https://github.com/hapifhir/org.hl7.fhir.core/pull/750


Last updated: Apr 12 2022 at 19:14 UTC