From c5634c012eca19a5309315e34f18ad74bdac2d9d Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Tue, 2 Jun 2020 13:51:41 +1000 Subject: [PATCH 1/4] Questionnaire Rendering improvements --- .../r5/renderers/QuestionnaireRenderer.java | 66 +++++++++++-------- 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireRenderer.java index db4d77261..da40e77f2 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireRenderer.java @@ -69,8 +69,12 @@ public class QuestionnaireRenderer extends TerminologyRenderer { model.getTitles().add(gen.new Title(null, model.getDocoRef(), translate("sd.head", "Description & Constraints"), translate("sd.hint", "Additional information about the item"), null, 0)); boolean hasExt = false; - for (QuestionnaireItemComponent i : q.getItem()) { - hasExt = renderTreeItem(gen, model.getRows(), q, i) || hasExt; + if (!q.hasItem()) { + gen.emptyRow(model, 6); + } else { + for (QuestionnaireItemComponent i : q.getItem()) { + hasExt = renderTreeItem(gen, model.getRows(), q, i) || hasExt; + } } XhtmlNode xn = gen.generate(model, context.getLocalPrefix(), 1, null); x.getChildNodes().add(xn); @@ -83,7 +87,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer { boolean hasExt = false; r.setIcon("icon-q-"+i.getType().toCode()+".png", i.getType().getDisplay()); - r.getCells().add(gen.new Cell(null, context.getDefinitionsTarget() == null ? "" : context.getDefinitionsTarget()+"-definitions.html#extension."+i.getLinkId(), i.getLinkId(), null, null)); + r.getCells().add(gen.new Cell(null, context.getDefinitionsTarget() == null ? "" : context.getDefinitionsTarget()+"#item."+i.getLinkId(), i.getLinkId(), null, null)); String txt = (i.hasPrefix() ? i.getPrefix() + ". " : "") + i.getText(); r.getCells().add(gen.new Cell(null, null, txt, null, null)); r.getCells().add(gen.new Cell(null, null, (i.getRequired() ? "1" : "0")+".."+(i.getRepeats() ? "*" : "1"), null, null)); @@ -93,28 +97,28 @@ public class QuestionnaireRenderer extends TerminologyRenderer { Cell flags = gen.new Cell(); r.getCells().add(flags); if (i.getReadOnly()) { - flags.addPiece(gen.new Piece(Utilities.pathURL(context.getSpecificationLink(), "questionnaire-definitions.html#Questionnaire.item.readOnly"), null, "Is Readonly").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getDestDir(), "icon-qi-readonly.png")))); + flags.addPiece(gen.new Piece(Utilities.pathURL(context.getSpecificationLink(), "questionnaire-definitions.html#Questionnaire.item.readOnly"), null, "Is Readonly").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-readonly.png")))); } if (ToolingExtensions.readBoolExtension(i, "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-isSubject")) { - flags.addPiece(gen.new Piece("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-isSubject", null, "Can change the subject of the questionnaire").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getDestDir(), "icon-qi-subject.png")))); + flags.addPiece(gen.new Piece("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-isSubject", null, "Can change the subject of the questionnaire").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-subject.png")))); } if (ToolingExtensions.readBoolExtension(i, "http://hl7.org/fhir/StructureDefinition/questionnaire-hidden")) { - flags.addPiece(gen.new Piece(Utilities.pathURL(context.getSpecificationLink(), "extension-questionnaire-hidden.html"), null, "Is a hidden item").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getDestDir(), "icon-qi-hidden.png")))); + flags.addPiece(gen.new Piece(Utilities.pathURL(context.getSpecificationLink(), "extension-questionnaire-hidden.html"), null, "Is a hidden item").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-hidden.png")))); } if (ToolingExtensions.readBoolExtension(i, "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-optionalDisplay")) { - flags.addPiece(gen.new Piece("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-optionalDisplay", null, "Is optional to display").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getDestDir(), "icon-qi-optional.png")))); + flags.addPiece(gen.new Piece("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-optionalDisplay", null, "Is optional to display").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-optional.png")))); } if (i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod")) { - flags.addPiece(gen.new Piece("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod", null, "Is linked to an observation").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getDestDir(), "icon-qi-observation.png")))); + flags.addPiece(gen.new Piece("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod", null, "Is linked to an observation").addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-observation.png")))); } if (i.hasExtension("http://hl7.org/fhir/StructureDefinition/questionnaire-choiceOrientation")) { String code = ToolingExtensions.readStringExtension(i, "http://hl7.org/fhir/StructureDefinition/questionnaire-choiceOrientation"); - flags.addPiece(gen.new Piece("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod", null, "Orientation: "+code).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getDestDir(), "icon-qi-"+code+".png")))); + flags.addPiece(gen.new Piece("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod", null, "Orientation: "+code).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-"+code+".png")))); } if (i.hasExtension("http://hl7.org/fhir/StructureDefinition/questionnaire-displayCategory")) { CodeableConcept cc = i.getExtensionByUrl("http://hl7.org/fhir/StructureDefinition/questionnaire-displayCategory").getValueCodeableConcept(); String code = cc.getCode("http://hl7.org/fhir/questionnaire-display-category"); - flags.addPiece(gen.new Piece("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-displayCategory", null, "Category: "+code).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getDestDir(), "icon-qi-"+code+".png")))); + flags.addPiece(gen.new Piece("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-displayCategory", null, "Category: "+code).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-"+code+".png")))); } Cell defn = gen.new Cell(); @@ -143,7 +147,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer { if (vs == null) { defn.getPieces().add(gen.new Piece(null, i.getAnswerValueSet(), null)); } else { - defn.getPieces().add(gen.new Piece("todo", vs.present(), null)); + defn.getPieces().add(gen.new Piece(vs.getUserString("path"), vs.present(), null)); } } else { ValueSet vs = context.getWorker().fetchResource(ValueSet.class, i.getAnswerValueSet()); @@ -157,7 +161,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer { if (i.hasAnswerOption()) { if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); defn.getPieces().add(gen.new Piece(null, "Options: ", null)); - defn.getPieces().add(gen.new Piece(context.getDefinitionsTarget()+"#"+i.getLinkId(), Integer.toString(i.getAnswerOption().size())+" "+Utilities.pluralize("option", i.getAnswerOption().size()), null)); + defn.getPieces().add(gen.new Piece(context.getDefinitionsTarget()+"#item."+i.getLinkId(), Integer.toString(i.getAnswerOption().size())+" "+Utilities.pluralize("option", i.getAnswerOption().size()), null)); } if (i.hasInitial()) { for (QuestionnaireItemInitialComponent v : i.getInitial()) { @@ -231,8 +235,12 @@ public class QuestionnaireRenderer extends TerminologyRenderer { model.getTitles().add(gen.new Title(null, model.getDocoRef(), translate("sd.head", "Description & Constraints"), translate("sd.hint", "Additional information about the item"), null, 0)); boolean hasExt = false; - for (QuestionnaireItemComponent i : q.getItem()) { - hasExt = renderLogicItem(gen, model.getRows(), q, i) || hasExt; + if (!q.hasItem()) { + gen.emptyRow(model, 2); + } else { + for (QuestionnaireItemComponent i : q.getItem()) { + hasExt = renderLogicItem(gen, model.getRows(), q, i) || hasExt; + } } XhtmlNode xn = gen.generate(model, context.getDestDir(), 1, null); x.getChildNodes().add(xn); @@ -245,7 +253,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer { boolean hasExt = false; r.setIcon("icon-q-"+i.getType().toCode()+".png", i.getType().getDisplay()); - r.getCells().add(gen.new Cell(null, context.getDefinitionsTarget() == null ? "" : context.getDefinitionsTarget()+"-definitions.html#extension."+i.getLinkId(), i.getLinkId(), null, null)); + r.getCells().add(gen.new Cell(null, context.getDefinitionsTarget() == null ? "" : context.getDefinitionsTarget()+"#item."+i.getLinkId(), i.getLinkId(), null, null)); Cell defn = gen.new Cell(); r.getCells().add(defn); @@ -272,7 +280,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer { if (vs == null) { defn.getPieces().add(gen.new Piece(null, i.getAnswerValueSet(), null)); } else { - defn.getPieces().add(gen.new Piece("todo", vs.present(), null)); + defn.getPieces().add(gen.new Piece(vs.getUserString("path"), vs.present(), null)); } } else { ValueSet vs = context.getWorker().fetchResource(ValueSet.class, i.getAnswerValueSet()); @@ -286,7 +294,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer { if (i.hasAnswerOption()) { if (!defn.getPieces().isEmpty()) defn.addPiece(gen.new Piece("br")); defn.getPieces().add(gen.new Piece(null, "Options: ", null)); - defn.getPieces().add(gen.new Piece(context.getDefinitionsTarget()+"#"+i.getLinkId(), Integer.toString(i.getAnswerOption().size())+" "+Utilities.pluralize("option", i.getAnswerOption().size()), null)); + defn.getPieces().add(gen.new Piece(context.getDefinitionsTarget()+"#item."+i.getLinkId(), Integer.toString(i.getAnswerOption().size())+" "+Utilities.pluralize("option", i.getAnswerOption().size()), null)); } if (i.hasInitial()) { for (QuestionnaireItemInitialComponent v : i.getInitial()) { @@ -459,7 +467,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer { // if (i.hasExtension("http://hl7.org/fhir/StructureDefinition/questionnaire-choiceOrientation")) { // String code = ToolingExtensions.readStringExtension(i, "http://hl7.org/fhir/StructureDefinition/questionnaire-choiceOrientation"); -// flags.addPiece(gen.new Piece("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod", null, "Orientation: "+code).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getDestDir(), "icon-qi-"+code+".png")))); +// flags.addPiece(gen.new Piece("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod", null, "Orientation: "+code).addHtml(new XhtmlNode(NodeType.Element, "img").attribute("src", Utilities.path(context.getLocalPrefix(), "icon-qi-"+code+".png")))); //} @@ -470,26 +478,26 @@ public class QuestionnaireRenderer extends TerminologyRenderer { if (ToolingExtensions.readBoolExtension(i, "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-isSubject")) { hasFlag = true; - flags.ah("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-isSubject", "Can change the subject of the questionnaire").img(Utilities.path(context.getDestDir(), "icon-qi-subject.png")); + flags.ah("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-isSubject", "Can change the subject of the questionnaire").img(Utilities.path(context.getLocalPrefix(), "icon-qi-subject.png")); } if (ToolingExtensions.readBoolExtension(i, "http://hl7.org/fhir/StructureDefinition/questionnaire-hidden")) { hasFlag = true; - flags.ah(Utilities.pathURL(context.getSpecificationLink(), "extension-questionnaire-hidden.html"), "Is a hidden item").img(Utilities.path(context.getDestDir(), "icon-qi-hidden.png")); + flags.ah(Utilities.pathURL(context.getSpecificationLink(), "extension-questionnaire-hidden.html"), "Is a hidden item").img(Utilities.path(context.getLocalPrefix(), "icon-qi-hidden.png")); d.style("background-color: #eeeeee"); } if (ToolingExtensions.readBoolExtension(i, "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-optionalDisplay")) { hasFlag = true; - flags.ah("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-optionalDisplay", "Is optional to display").img(Utilities.path(context.getDestDir(), "icon-qi-optional.png")); + flags.ah("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-optionalDisplay", "Is optional to display").img(Utilities.path(context.getLocalPrefix(), "icon-qi-optional.png")); } if (i.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod")) { hasFlag = true; - flags.ah("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod", "Is linked to an observation").img(Utilities.path(context.getDestDir(), "icon-qi-observation.png")); + flags.ah("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationLinkPeriod", "Is linked to an observation").img(Utilities.path(context.getLocalPrefix(), "icon-qi-observation.png")); } if (i.hasExtension("http://hl7.org/fhir/StructureDefinition/questionnaire-displayCategory")) { CodeableConcept cc = i.getExtensionByUrl("http://hl7.org/fhir/StructureDefinition/questionnaire-displayCategory").getValueCodeableConcept(); String code = cc.getCode("http://hl7.org/fhir/questionnaire-display-category"); hasFlag = true; - flags.ah("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-displayCategory", "Category: "+code).img(Utilities.path(context.getDestDir(), "icon-qi-"+code+".png")); + flags.ah("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-displayCategory", "Category: "+code).img(Utilities.path(context.getLocalPrefix(), "icon-qi-"+code+".png")); } if (i.hasMaxLength()) { @@ -508,7 +516,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer { if (vs == null) { ans.tx(i.getAnswerValueSet()); } else { - ans.ah("todo").tx(vs.present()); + ans.ah(vs.getUserString("path")).tx(vs.present()); } } else { ValueSet vs = context.getWorker().fetchResource(ValueSet.class, i.getAnswerValueSet()); @@ -520,7 +528,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer { } } if (i.hasAnswerOption()) { - item(ul, "Answers", Integer.toString(i.getAnswerOption().size())+" "+Utilities.pluralize("option", i.getAnswerOption().size()), context.getDefinitionsTarget()+"#"+i.getLinkId()); + item(ul, "Answers", Integer.toString(i.getAnswerOption().size())+" "+Utilities.pluralize("option", i.getAnswerOption().size()), context.getDefinitionsTarget()+"#item."+i.getLinkId()); } if (i.hasInitial()) { XhtmlNode vi = item(ul, "Initial Values"); @@ -642,12 +650,12 @@ public class QuestionnaireRenderer extends TerminologyRenderer { private boolean renderDefinition(XhtmlNode tbl, Questionnaire q, QuestionnaireItemComponent qi, List parents) throws IOException { boolean ext = false; XhtmlNode td = tbl.tr().td("structure").colspan("2").span(null, null).attribute("class", "self-link-parent"); - td.an(qi.getLinkId()); + td.an("item."+qi.getLinkId()); for (QuestionnaireItemComponent p : parents) { - td.ah("#"+p.getLinkId()).img(Utilities.path(context.getDestDir(), "icon_q_item.png")); + td.ah("#item."+p.getLinkId()).img(Utilities.path(context.getLocalPrefix(), "icon_q_item.png")); td.tx(" > "); } - td.img(Utilities.path(context.getDestDir(), "icon_q_item.png")); + td.img(Utilities.path(context.getLocalPrefix(), "icon_q_item.png")); td.tx(" Item "); td.b().tx(qi.getLinkId()); @@ -767,7 +775,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer { } private void renderEnableWhen(XhtmlNode x, QuestionnaireItemEnableWhenComponent ew) { - x.ah("#"+ew.getQuestion()).tx(ew.getQuestion()); + x.ah("#item."+ew.getQuestion()).tx(ew.getQuestion()); x.tx(" "); x.tx(ew.getOperator().toCode()); x.tx(" "); From f1d901a842965b4ad6a08ea66b4c22442b085357 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Tue, 2 Jun 2020 13:52:28 +1000 Subject: [PATCH 2/4] Support for rendering contained resources in IG Publisher --- .../main/java/org/hl7/fhir/r5/model/Base.java | 9 +++ .../org/hl7/fhir/r5/test/XmlParserTests.java | 65 +++++++++++++++++++ .../xhtml/HierarchicalTableGenerator.java | 8 +++ 3 files changed, 82 insertions(+) create mode 100644 org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/XmlParserTests.java diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Base.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Base.java index 3b0394915..3d0a9180d 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Base.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Base.java @@ -79,6 +79,15 @@ private Map userData; return (Integer) getUserData(name); } + public void copyUserData(Base other) { + if (other.userData != null) { + if (userData == null) { + userData = new HashMap<>(); + } + userData.putAll(other.userData); + } + } + public boolean hasFormatComment() { return (formatCommentsPre != null && !formatCommentsPre.isEmpty()) || (formatCommentsPost != null && !formatCommentsPost.isEmpty()); } diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/XmlParserTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/XmlParserTests.java new file mode 100644 index 000000000..97a5c119a --- /dev/null +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/XmlParserTests.java @@ -0,0 +1,65 @@ +package org.hl7.fhir.r5.test; + +import static org.junit.Assert.assertTrue; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import org.hl7.fhir.r5.context.SimpleWorkerContext; +import org.hl7.fhir.r5.elementmodel.Element; +import org.hl7.fhir.r5.elementmodel.Manager; +import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat; +import org.hl7.fhir.r5.formats.IParser.OutputStyle; +import org.hl7.fhir.r5.model.StructureDefinition; +import org.hl7.fhir.r5.test.utils.TestingUtilities; +import org.hl7.fhir.r5.utils.FHIRPathEngine; +import org.hl7.fhir.utilities.cache.PackageCacheManager; +import org.hl7.fhir.utilities.cache.ToolsVersion; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class XmlParserTests { + + private static SimpleWorkerContext context; + private static FHIRPathEngine fp; + + @BeforeAll + public static void setUp() throws Exception { + PackageCacheManager pcm = new PackageCacheManager(true, ToolsVersion.TOOLS_VERSION); + context = SimpleWorkerContext.fromPackage(pcm.loadPackage("hl7.fhir.r4.core", "4.0.1")); + fp = new FHIRPathEngine(context); + + context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "any.xml"), "any.xml", null); + context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "ii.xml"), "ii.xml", null); + context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "cd.xml"), "cd.xml", null); + context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "ce.xml"), "ce.xml", null); + context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "ed.xml"), "ed.xml", null); + context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "st.xml"), "st.xml", null); + context.loadFromFile(TestingUtilities.loadTestResourceStream("validator", "cda", "cda.xml"), "cda.xml", null); + for (StructureDefinition sd : context.getStructures()) { + if (!sd.hasSnapshot()) { + System.out.println("generate snapshot for " + sd.getUrl()); + context.generateSnapshot(sd, true); + } + } + } + + @Test + /** + * Deserializes a simplified CDA example into the logical model and checks that + * xml deserialization works for the xsi:type + * + * @throws IOException + */ + public void testXsiDeserialiserXmlParser() throws IOException { + Element cda = Manager.parse(context, TestingUtilities.loadTestResourceStream("validator", "cda", "example-xsi.xml"), + FhirFormat.XML); + + ByteArrayOutputStream baosXml = new ByteArrayOutputStream(); + Manager.compose(context, cda, baosXml, FhirFormat.XML, OutputStyle.PRETTY, null); + + String cdaSerialised = baosXml.toString(); + assertTrue(cdaSerialised.indexOf("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"")>0); + assertTrue(cdaSerialised.indexOf("xsi:type=\"CD\"")>0); + } +} \ No newline at end of file diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/HierarchicalTableGenerator.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/HierarchicalTableGenerator.java index 5d2dba4de..bb1dea0da 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/HierarchicalTableGenerator.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/HierarchicalTableGenerator.java @@ -917,4 +917,12 @@ public class HierarchicalTableGenerator extends TranslatingUtilities { if (!check) throw new FHIRException(message); } + + public void emptyRow(TableModel model, int cellCount) { + Row r = new Row(); + model.rows.add(r); + for (int i = 0; i < cellCount; i++) { + r.getCells().add(new Cell()); + } + } } \ No newline at end of file From 211ac8fc12c113b3d9d3a855d2df474d5845b804 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Tue, 2 Jun 2020 18:21:09 +1000 Subject: [PATCH 3/4] fix bug processing profiles for v1.4.0 --- .../main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java index 29e141bd9..c30565bf9 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/BaseWorkerContext.java @@ -309,7 +309,9 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte for (ElementDefinition ed : sd.getDifferential().getElement()) { if (ed.getPath().equals("Extension.url") || ed.getPath().endsWith(".extension.url") ) { ed.setMin(1); - ed.getBase().setMin(1); + if (ed.hasBase()) { + ed.getBase().setMin(1); + } } if ("extension".equals(ed.getSliceName())) { ed.setSliceName(null); From f169a4315ffbac96af051f59f9c7328b820952f8 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Tue, 2 Jun 2020 18:21:27 +1000 Subject: [PATCH 4/4] start working on R3 string functions --- .../org/hl7/fhir/r5/model/ExpressionNode.java | 20 +++-- .../org/hl7/fhir/r5/utils/FHIRPathEngine.java | 81 ++++++++++++++----- 2 files changed, 74 insertions(+), 27 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/ExpressionNode.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/ExpressionNode.java index db70fb227..6e68b7b73 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/ExpressionNode.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/ExpressionNode.java @@ -73,8 +73,10 @@ public class ExpressionNode { First, Last, Tail, Skip, Take, Union, Combine, Intersect, Exclude, Iif, Upper, Lower, ToChars, IndexOf, Substring, StartsWith, EndsWith, Matches, ReplaceMatches, Contains, Replace, Length, Children, Descendants, MemberOf, Trace, Check, Today, Now, Resolve, Extension, AllFalse, AnyFalse, AllTrue, AnyTrue, HasValue, OfType, Type, ConvertsToBoolean, ConvertsToInteger, ConvertsToString, ConvertsToDecimal, ConvertsToQuantity, ConvertsToDateTime, ConvertsToTime, ToBoolean, ToInteger, ToString, ToDecimal, ToQuantity, ToDateTime, ToTime, ConformsTo, + // R3 functions + Encode, Decode, Escape, Trim, Split, Join, // Local extensions to FHIRPath - HtmlChecks, AliasAs, Alias, fromBase64, toBase64; + HtmlChecks, AliasAs, Alias; public static Function fromCode(String name) { if (name.equals("empty")) return Function.Empty; @@ -134,8 +136,12 @@ public class ExpressionNode { if (name.equals("aliasAs")) return Function.AliasAs; if (name.equals("htmlChecks")) return Function.HtmlChecks; if (name.equals("htmlchecks")) return Function.HtmlChecks; // support change of care from R3 - if (name.equals("fromBase64")) return Function.fromBase64; - if (name.equals("toBase64")) return Function.toBase64; + if (name.equals("encode")) return Function.Encode; + if (name.equals("decode")) return Function.Decode; + if (name.equals("escape")) return Function.Escape; + if (name.equals("trim")) return Function.Trim; + if (name.equals("split")) return Function.Split; + if (name.equals("join")) return Function.Join; if (name.equals("ofType")) return Function.OfType; if (name.equals("type")) return Function.Type; if (name.equals("toInteger")) return Function.ToInteger; @@ -212,8 +218,12 @@ public class ExpressionNode { case HasValue : return "hasValue"; case Alias : return "alias"; case AliasAs : return "aliasAs"; - case fromBase64 : return "fromBase64"; - case toBase64 : return "toBase64"; + case Encode : return "encode"; + case Decode : return "decode"; + case Escape : return "escape"; + case Trim : return "trim"; + case Split : return "split"; + case Join : return "join"; case HtmlChecks : return "htmlChecks"; case OfType : return "ofType"; case Type : return "type"; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java index d53d2f412..6858ba088 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/FHIRPathEngine.java @@ -1147,8 +1147,12 @@ public class FHIRPathEngine { case HasValue: return checkParamCount(lexer, location, exp, 0); case Alias: return checkParamCount(lexer, location, exp, 1); case AliasAs: return checkParamCount(lexer, location, exp, 1); - case fromBase64: return checkParamCount(lexer, location, exp, 0); - case toBase64: return checkParamCount(lexer, location, exp, 0); + case Encode: return checkParamCount(lexer, location, exp, 1); + case Decode: return checkParamCount(lexer, location, exp, 1); + case Escape: return checkParamCount(lexer, location, exp, 1); + case Trim: return checkParamCount(lexer, location, exp, 0); + case Split: return checkParamCount(lexer, location, exp, 1); + case Join: return checkParamCount(lexer, location, exp, 1); case HtmlChecks: return checkParamCount(lexer, location, exp, 0); case ToInteger: return checkParamCount(lexer, location, exp, 0); case ToDecimal: return checkParamCount(lexer, location, exp, 0); @@ -2646,10 +2650,23 @@ public class FHIRPathEngine { return anything(CollectionStatus.SINGLETON); case AliasAs : checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); - return focus; - case fromBase64: + return focus; + case Encode: + checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); - case toBase64: + case Decode: + checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); + case Escape: + checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); + case Trim: + return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); + case Split: + checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); + return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); + case Join: + checkParamTypes(exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String); case ToInteger : { checkContextPrimitive(focus, "toInteger", true); @@ -2825,8 +2842,12 @@ public class FHIRPathEngine { case AllTrue: return funcAllTrue(context, focus, exp); case HasValue : return funcHasValue(context, focus, exp); case AliasAs : return funcAliasAs(context, focus, exp); - case fromBase64 : return funcFromBase64(context, focus, exp); - case toBase64 : return funcToBase64(context, focus, exp); + case Encode : return funcEncode(context, focus, exp); + case Decode : return funcDecode(context, focus, exp); + case Escape : return funcEscape(context, focus, exp); + case Trim : return funcTrim(context, focus, exp); + case Split : return funcSplit(context, focus, exp); + case Join : return funcJoin(context, focus, exp); case Alias : return funcAlias(context, focus, exp); case HtmlChecks : return funcHtmlChecks(context, focus, exp); case ToInteger : return funcToInteger(context, focus, exp); @@ -2854,27 +2875,43 @@ public class FHIRPathEngine { throw new Error("not Implemented yet"); } } + + private List funcEncode(ExecutionContext context, List focus, ExpressionNode exp) { + List result = new ArrayList(); + + return result; + } - private List funcToBase64(ExecutionContext context, List focus, ExpressionNode exp) { - List result = new ArrayList(); - if (focus.size() == 1) { - String s = convertToString(focus.get(0)); - result.add(new StringType(Base64.encodeBase64String(s.getBytes()))); - } - return result; + private List funcDecode(ExecutionContext context, List focus, ExpressionNode exp) { + List result = new ArrayList(); + + return result; } - - private List funcFromBase64(ExecutionContext context, List focus, ExpressionNode exp) { - List result = new ArrayList(); - if (focus.size() == 1) { - String s = convertToString(focus.get(0)); - result.add(new StringType(new String(Base64.decodeBase64(s)))); - } - return result; + private List funcEscape(ExecutionContext context, List focus, ExpressionNode exp) { + List result = new ArrayList(); + + return result; } + private List funcTrim(ExecutionContext context, List focus, ExpressionNode exp) { + List result = new ArrayList(); + + return result; + } + private List funcSplit(ExecutionContext context, List focus, ExpressionNode exp) { + List result = new ArrayList(); + + return result; + } + + private List funcJoin(ExecutionContext context, List focus, ExpressionNode exp) { + List result = new ArrayList(); + + return result; + } + private List funcAliasAs(ExecutionContext context, List focus, ExpressionNode exp) throws FHIRException { List nl = execute(context, focus, exp.getParameters().get(0), true); String name = nl.get(0).primitiveValue();