fixes for 5.1.8 (#336)

* Fix up conversion for date problems

* Mark packages as unsuitable for publication

* rework rendering tests & fix bug in Parameters renderer

* fix test case depedency

* update VSACImporter to get value sets from VSAC directly

* Fix up rendering of Extensions

* Add support for choice groups, and markdownify some elements
This commit is contained in:
Grahame Grieve 2020-09-04 23:49:36 +10:00 committed by GitHub
parent 6cf6367b30
commit 7ca698f36a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 675 additions and 178 deletions

View File

@ -65,6 +65,7 @@ import org.hl7.fhir.convertors.conv10_40.ValueSet10_40;
import org.hl7.fhir.dstu2.model.CodeableConcept; import org.hl7.fhir.dstu2.model.CodeableConcept;
import org.hl7.fhir.dstu2.model.Parameters; import org.hl7.fhir.dstu2.model.Parameters;
import org.hl7.fhir.dstu2.model.Parameters.ParametersParameterComponent; import org.hl7.fhir.dstu2.model.Parameters.ParametersParameterComponent;
import org.hl7.fhir.dstu2.model.PositiveIntType;
import org.hl7.fhir.dstu2.model.Reference; import org.hl7.fhir.dstu2.model.Reference;
import org.hl7.fhir.dstu2.utils.ToolingExtensions; import org.hl7.fhir.dstu2.utils.ToolingExtensions;
import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRException;
@ -3423,4 +3424,10 @@ public class VersionConvertor_10_40 {
public static org.hl7.fhir.dstu2.model.Resource convertResource(org.hl7.fhir.r4.model.Resource src) throws FHIRException { public static org.hl7.fhir.dstu2.model.Resource convertResource(org.hl7.fhir.r4.model.Resource src) throws FHIRException {
return convertResource(src, null); return convertResource(src, null);
} }
public static UnsignedIntType convertUnsignedIntToPositive(PositiveIntType src) {
org.hl7.fhir.r4.model.UnsignedIntType tgt = src.hasValue() ? new org.hl7.fhir.r4.model.UnsignedIntType(src.getValue()) : new org.hl7.fhir.r4.model.UnsignedIntType();
copyElement(src, tgt);
return tgt;
}
} }

View File

@ -15,7 +15,7 @@ public class MedicationRequest10_40 {
tgt.setIntent(org.hl7.fhir.r4.model.MedicationRequest.MedicationRequestIntent.ORDER); tgt.setIntent(org.hl7.fhir.r4.model.MedicationRequest.MedicationRequestIntent.ORDER);
for (org.hl7.fhir.dstu2.model.Identifier identifier : src.getIdentifier()) tgt.addIdentifier(VersionConvertor_10_40.convertIdentifier(identifier)); for (org.hl7.fhir.dstu2.model.Identifier identifier : src.getIdentifier()) tgt.addIdentifier(VersionConvertor_10_40.convertIdentifier(identifier));
if (src.hasDateWritten()) if (src.hasDateWritten())
tgt.setAuthoredOn(src.getDateWritten()); tgt.setAuthoredOnElement(VersionConvertor_10_40.convertDateTime(src.getDateWrittenElement()));
if (src.hasStatus()) if (src.hasStatus())
tgt.setStatus(org.hl7.fhir.r4.model.MedicationRequest.MedicationRequestStatus.fromCode(src.getStatus().toCode())); tgt.setStatus(org.hl7.fhir.r4.model.MedicationRequest.MedicationRequestStatus.fromCode(src.getStatus().toCode()));
if (src.hasPatient()) if (src.hasPatient())
@ -48,7 +48,7 @@ public class MedicationRequest10_40 {
return null; return null;
org.hl7.fhir.r4.model.Dosage tgt = new org.hl7.fhir.r4.model.Dosage(); org.hl7.fhir.r4.model.Dosage tgt = new org.hl7.fhir.r4.model.Dosage();
if (src.hasText()) if (src.hasText())
tgt.setText(src.getText()); tgt.setTextElement(VersionConvertor_10_40.convertString(src.getTextElement()));
if (src.hasAdditionalInstructions()) if (src.hasAdditionalInstructions())
tgt.addAdditionalInstruction(VersionConvertor_10_40.convertCodeableConcept(src.getAdditionalInstructions())); tgt.addAdditionalInstruction(VersionConvertor_10_40.convertCodeableConcept(src.getAdditionalInstructions()));
if (src.hasTiming()) if (src.hasTiming())
@ -79,7 +79,7 @@ public class MedicationRequest10_40 {
if (src.hasValidityPeriod()) if (src.hasValidityPeriod())
tgt.setValidityPeriod(VersionConvertor_10_40.convertPeriod(src.getValidityPeriod())); tgt.setValidityPeriod(VersionConvertor_10_40.convertPeriod(src.getValidityPeriod()));
if (src.hasNumberOfRepeatsAllowed()) if (src.hasNumberOfRepeatsAllowed())
tgt.setNumberOfRepeatsAllowed(src.getNumberOfRepeatsAllowed()); tgt.setNumberOfRepeatsAllowedElement(VersionConvertor_10_40.convertUnsignedIntToPositive(src.getNumberOfRepeatsAllowedElement()));
if (src.hasQuantity()) if (src.hasQuantity())
tgt.setQuantity(VersionConvertor_10_40.convertSimpleQuantity(src.getQuantity())); tgt.setQuantity(VersionConvertor_10_40.convertSimpleQuantity(src.getQuantity()));
if (src.hasExpectedSupplyDuration()) if (src.hasExpectedSupplyDuration())

View File

@ -1,26 +1,29 @@
package org.hl7.fhir.convertors.misc; package org.hl7.fhir.convertors.misc;
import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.formats.JsonParser; import org.hl7.fhir.r4.utils.client.FHIRToolingClient;
import org.hl7.fhir.r5.model.Enumerations.PublicationStatus; import org.hl7.fhir.r4.formats.JsonParser;
import org.hl7.fhir.r5.model.ValueSet; import org.hl7.fhir.r4.model.Enumerations.PublicationStatus;
import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent; import org.hl7.fhir.r4.model.ValueSet;
import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.utilities.CSVReader;
import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.xml.XMLUtil; import org.hl7.fhir.utilities.xml.XMLUtil;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import java.io.*; import java.io.*;
import java.net.URISyntaxException;
import java.text.ParseException; import java.text.ParseException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class VSACImporter extends OIDBasedValueSetImporter { public class VSACImporter extends OIDBasedValueSetImporter {
public static void main(String[] args) throws FileNotFoundException, FHIRException, IOException, ParseException { public static void main(String[] args) throws FileNotFoundException, FHIRException, IOException, ParseException, URISyntaxException {
// new PhinVadsImporter().importValueSet(TextFile.fileToBytes("C:\\work\\org.hl7.fhir\\packages\\us.cdc.phinvads-source\\source\\PHVS_BirthDefectsLateralityatDiagnosis_HL7_V1.txt")); // new PhinVadsImporter().importValueSet(TextFile.fileToBytes("C:\\work\\org.hl7.fhir\\packages\\us.cdc.phinvads-source\\source\\PHVS_BirthDefectsLateralityatDiagnosis_HL7_V1.txt"));
VSACImporter self = new VSACImporter(); VSACImporter self = new VSACImporter();
self.process(args[0], args[1]); self.process(args[0], args[1], args[2], args[3]);
} }
public VSACImporter() throws FileNotFoundException, FHIRException, IOException { public VSACImporter() throws FileNotFoundException, FHIRException, IOException {
@ -28,69 +31,87 @@ public class VSACImporter extends OIDBasedValueSetImporter {
init(); init();
} }
private void process(String source, String dest) { private void process(String source, String dest, String username, String password) throws FHIRException, FileNotFoundException, IOException, URISyntaxException {
for (File f : new File(source).listFiles()) { CSVReader csv = new CSVReader(new FileInputStream(source));
csv.readHeaders();
FHIRToolingClient client = new FHIRToolingClient("https://cts.nlm.nih.gov/fhir", username, password);
int i = 0;
while (csv.line()) {
String oid = csv.cell("OID");
try { try {
System.out.println("Process " + f.getName()); ValueSet vs = client.read(ValueSet.class, oid);
List<ValueSet> vsl = importValueSet(TextFile.fileToBytes(f)); new JsonParser().compose(new FileOutputStream(Utilities.path(dest, "ValueSet-"+oid+".json")), vs);
for (ValueSet vs : vsl) { i++;
if (vs.getId() != null) { if (i % 100 == 0) {
new JsonParser().compose(new FileOutputStream(Utilities.path(dest, "ValueSet-" + vs.getId() + ".json")), vs); System.out.println(i);
}
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); System.out.println("Unable to fetch OID "+oid+": "+e.getMessage());
} }
} }
System.out.println("Done. "+i+" ValueSets");
// for (File f : new File(source).listFiles()) {
// try {
// System.out.println("Process " + f.getName());
// List<ValueSet> vsl = importValueSet(TextFile.fileToBytes(f));
// for (ValueSet vs : vsl) {
// if (vs.getId() != null) {
// new JsonParser().compose(new FileOutputStream(Utilities.path(dest, "ValueSet-" + vs.getId() + ".json")), vs);
// }
// }
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
} }
private List<ValueSet> importValueSet(byte[] source) throws Exception { // private List<ValueSet> importValueSet(byte[] source) throws Exception {
List<ValueSet> res = new ArrayList<ValueSet>(); // List<ValueSet> res = new ArrayList<ValueSet>();
Element x = loadXml(new ByteArrayInputStream(source)).getDocumentElement(); // Element x = loadXml(new ByteArrayInputStream(source)).getDocumentElement();
List<Element> vl = XMLUtil.getNamedChildren(x, "DescribedValueSet"); // List<Element> vl = XMLUtil.getNamedChildren(x, "DescribedValueSet");
for (Element v : vl) { // for (Element v : vl) {
ValueSet vs = new ValueSet(); // ValueSet vs = new ValueSet();
vs.setId(v.getAttribute("ID")); // vs.setId(v.getAttribute("ID"));
vs.setUrl("http://vsac.nlm.nih.gov/fhir/ValueSet/" + vs.getId()); // vs.setUrl("http://cts.nlm.nih.gov/fhir/ValueSet/" + vs.getId());
vs.getMeta().setSource("https://vsac.nlm.nih.gov/valueset/" + vs.getId() + "/expansion"); // vs.getMeta().setSource("https://vsac.nlm.nih.gov/valueset/" + vs.getId() + "/expansion");
vs.setVersion(v.getAttribute("version")); // vs.setVersion(v.getAttribute("version"));
vs.setTitle(v.getAttribute("displayName")); // vs.setTitle(v.getAttribute("displayName"));
vs.setName(Utilities.titleize(vs.getTitle()).replace(" ", "")); // vs.setName(Utilities.titleize(vs.getTitle()).replace(" ", ""));
Element d = XMLUtil.getNamedChild(v, "Purpose"); // Element d = XMLUtil.getNamedChild(v, "Purpose");
if (d != null) { // if (d != null) {
vs.setDescription(d.getTextContent()); // vs.setDescription(d.getTextContent());
} // }
Element s = XMLUtil.getNamedChild(v, "Status"); // Element s = XMLUtil.getNamedChild(v, "Status");
if (s != null && "Active".equals(s.getTextContent())) { // if (s != null && "Active".equals(s.getTextContent())) {
vs.setStatus(PublicationStatus.ACTIVE); // vs.setStatus(PublicationStatus.ACTIVE);
} else { // } else {
vs.setStatus(PublicationStatus.DRAFT); // vs.setStatus(PublicationStatus.DRAFT);
} // }
Element dt = XMLUtil.getNamedChild(v, "RevisionDate"); // Element dt = XMLUtil.getNamedChild(v, "RevisionDate");
if (dt != null) { // if (dt != null) {
vs.getDateElement().setValueAsString(dt.getTextContent()); // vs.getDateElement().setValueAsString(dt.getTextContent());
} // }
//
Element cl = XMLUtil.getNamedChild(v, "ConceptList"); // Element cl = XMLUtil.getNamedChild(v, "ConceptList");
Element cc = XMLUtil.getFirstChild(cl); // Element cc = XMLUtil.getFirstChild(cl);
//
while (cc != null) { // while (cc != null) {
String code = cc.getAttribute("code"); // String code = cc.getAttribute("code");
String display = cc.getAttribute("displayName"); // String display = cc.getAttribute("displayName");
String csoid = cc.getAttribute("codeSystem"); // String csoid = cc.getAttribute("codeSystem");
String csver = cc.getAttribute("codeSystemVersion"); // String csver = cc.getAttribute("codeSystemVersion");
String url = context.oid2Uri(csoid); // String url = context.oid2Uri(csoid);
if (url == null) { // if (url == null) {
url = "urn:oid:" + csoid; // url = "urn:oid:" + csoid;
} // }
csver = fixVersionforSystem(url, csver); // csver = fixVersionforSystem(url, csver);
ConceptSetComponent inc = getInclude(vs, url, csver); // ConceptSetComponent inc = getInclude(vs, url, csver);
inc.addConcept().setCode(code).setDisplay(display); // inc.addConcept().setCode(code).setDisplay(display);
cc = XMLUtil.getNextSibling(cc); // cc = XMLUtil.getNextSibling(cc);
} // }
//
res.add(vs); // res.add(vs);
} // }
return res; // return res;
} // }
} }

View File

@ -78,6 +78,9 @@ import org.hl7.fhir.r5.model.Enumeration;
import org.hl7.fhir.r5.model.Enumerations.BindingStrength; import org.hl7.fhir.r5.model.Enumerations.BindingStrength;
import org.hl7.fhir.r5.model.Enumerations.FHIRVersion; import org.hl7.fhir.r5.model.Enumerations.FHIRVersion;
import org.hl7.fhir.r5.model.Enumerations.PublicationStatus; import org.hl7.fhir.r5.model.Enumerations.PublicationStatus;
import org.hl7.fhir.r5.model.ExpressionNode;
import org.hl7.fhir.r5.model.ExpressionNode.Kind;
import org.hl7.fhir.r5.model.ExpressionNode.Operation;
import org.hl7.fhir.r5.model.Extension; import org.hl7.fhir.r5.model.Extension;
import org.hl7.fhir.r5.model.IdType; import org.hl7.fhir.r5.model.IdType;
import org.hl7.fhir.r5.model.IntegerType; import org.hl7.fhir.r5.model.IntegerType;
@ -99,6 +102,8 @@ import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent; import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.r5.renderers.TerminologyRenderer; import org.hl7.fhir.r5.renderers.TerminologyRenderer;
import org.hl7.fhir.r5.terminologies.ValueSetExpander.ValueSetExpansionOutcome; import org.hl7.fhir.r5.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
import org.hl7.fhir.r5.utils.FHIRLexer;
import org.hl7.fhir.r5.utils.FHIRPathEngine;
import org.hl7.fhir.r5.utils.ToolingExtensions; import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.r5.utils.TranslatingUtilities; import org.hl7.fhir.r5.utils.TranslatingUtilities;
import org.hl7.fhir.r5.utils.XVerExtensionManager; import org.hl7.fhir.r5.utils.XVerExtensionManager;
@ -200,7 +205,31 @@ public class ProfileUtilities extends TranslatingUtilities {
} }
} }
public static class ElementChoiceGroup {
private Row row;
private String name;
private boolean mandatory;
private List<String> elements = new ArrayList<>();
public ElementChoiceGroup(String name, boolean mandatory) {
super();
this.name = name;
this.mandatory = mandatory;
}
public Row getRow() {
return row;
}
public List<String> getElements() {
return elements;
}
public void setRow(Row row) {
this.row = row;
}
public String getName() {
return name;
}
}
private static final int MAX_RECURSION_LIMIT = 10; private static final int MAX_RECURSION_LIMIT = 10;
public class ExtensionContext { public class ExtensionContext {
@ -268,6 +297,7 @@ public class ProfileUtilities extends TranslatingUtilities {
// note that ProfileUtilities are used re-entrantly internally, so nothing with process state can be here // note that ProfileUtilities are used re-entrantly internally, so nothing with process state can be here
private final IWorkerContext context; private final IWorkerContext context;
private FHIRPathEngine fpe;
private List<ValidationMessage> messages; private List<ValidationMessage> messages;
private List<String> snapshotStack = new ArrayList<String>(); private List<String> snapshotStack = new ArrayList<String>();
private ProfileKnowledgeProvider pkp; private ProfileKnowledgeProvider pkp;
@ -284,6 +314,9 @@ public class ProfileUtilities extends TranslatingUtilities {
this.context = context; this.context = context;
this.messages = messages; this.messages = messages;
this.pkp = pkp; this.pkp = pkp;
if (context != null) {
this.fpe = new FHIRPathEngine(context, this);
}
} }
public static class UnusedTracker { public static class UnusedTracker {
@ -538,6 +571,7 @@ public class ProfileUtilities extends TranslatingUtilities {
} }
processPaths("", derived.getSnapshot(), baseSnapshot, diff, baseCursor, diffCursor, baseSnapshot.getElement().size()-1, processPaths("", derived.getSnapshot(), baseSnapshot, diff, baseCursor, diffCursor, baseSnapshot.getElement().size()-1,
derived.getDifferential().hasElement() ? derived.getDifferential().getElement().size()-1 : -1, url, webUrl, derived.present(), null, null, false, base.getUrl(), null, false, null, new ArrayList<ElementRedirection>(), base); derived.getDifferential().hasElement() ? derived.getDifferential().getElement().size()-1 : -1, url, webUrl, derived.present(), null, null, false, base.getUrl(), null, false, null, new ArrayList<ElementRedirection>(), base);
checkGroupConstraints(derived);
if (derived.getDerivation() == TypeDerivationRule.SPECIALIZATION) { if (derived.getDerivation() == TypeDerivationRule.SPECIALIZATION) {
for (ElementDefinition e : diff.getElement()) { for (ElementDefinition e : diff.getElement()) {
if (!e.hasUserData(GENERATED_IN_SNAPSHOT)) { if (!e.hasUserData(GENERATED_IN_SNAPSHOT)) {
@ -666,6 +700,81 @@ public class ProfileUtilities extends TranslatingUtilities {
derived.clearUserData("profileutils.snapshot.generating"); derived.clearUserData("profileutils.snapshot.generating");
} }
private void checkGroupConstraints(StructureDefinition derived) {
List<ElementDefinition> toRemove = new ArrayList<>();
// List<ElementDefinition> processed = new ArrayList<>();
for (ElementDefinition element : derived.getSnapshot().getElement()) {
if (!toRemove.contains(element) && !element.hasSlicing() && !"0".equals(element.getMax())) {
checkForChildrenInGroup(derived, toRemove, element);
}
}
derived.getSnapshot().getElement().removeAll(toRemove);
}
public void checkForChildrenInGroup(StructureDefinition derived, List<ElementDefinition> toRemove, ElementDefinition element) throws Error {
List<ElementDefinition> children = getChildren(derived, element);
List<ElementChoiceGroup> groups = readChoices(element, children);
for (ElementChoiceGroup group : groups) {
System.out.println(children);
String mandated = null;
Set<String> names = new HashSet<>();
for (ElementDefinition ed : children) {
String name = tail(ed.getPath());
if (names.contains(name)) {
throw new Error("huh?");
} else {
names.add(name);
}
if (group.getElements().contains(name)) {
if (ed.getMin() == 1) {
if (mandated == null) {
mandated = name;
} else {
throw new Error("Error: there are two mandatory elements in "+derived.getUrl()+" when there can only be one: "+mandated+" and "+name);
}
}
}
}
if (mandated != null) {
for (ElementDefinition ed : children) {
String name = tail(ed.getPath());
if (group.getElements().contains(name) && !mandated.equals(name)) {
ed.setMax("0");
addAllChildren(derived, ed, toRemove);
}
}
}
}
}
private List<ElementDefinition> getChildren(StructureDefinition derived, ElementDefinition element) {
List<ElementDefinition> elements = derived.getSnapshot().getElement();
int index = elements.indexOf(element) + 1;
String path = element.getPath()+".";
List<ElementDefinition> list = new ArrayList<>();
while (index < elements.size()) {
ElementDefinition e = elements.get(index);
String p = e.getPath();
if (p.startsWith(path) && !e.hasSliceName()) {
if (!p.substring(path.length()).contains(".")) {
list.add(e);
}
index++;
} else {
break;
}
}
return list;
}
private void addAllChildren(StructureDefinition derived, ElementDefinition element, List<ElementDefinition> toRemove) {
List<ElementDefinition> children = getChildList(derived, element);
for (ElementDefinition child : children) {
toRemove.add(child);
addAllChildren(derived, child, toRemove);
}
}
private void checkDifferential(List<ElementDefinition> elements, String type, String url) { private void checkDifferential(List<ElementDefinition> elements, String type, String url) {
boolean first = true; boolean first = true;
for (ElementDefinition ed : elements) { for (ElementDefinition ed : elements) {
@ -3620,12 +3729,17 @@ public class ProfileUtilities extends TranslatingUtilities {
} }
Row currRow = row; Row currRow = row;
List<ElementChoiceGroup> groups = readChoices(element, children);
boolean isExtension = Utilities.existsInList(tail(element.getPath()), "extension", "modifierExtension"); boolean isExtension = Utilities.existsInList(tail(element.getPath()), "extension", "modifierExtension");
for (ElementDefinition child : children) { for (ElementDefinition child : children) {
if (!child.hasSliceName()) if (!child.hasSliceName()) {
currRow = row; currRow = row;
if (logicalModel || !child.getPath().endsWith(".id") || (child.getPath().endsWith(".id") && (profile != null) && (profile.getDerivation() == TypeDerivationRule.CONSTRAINT))) }
currRow = genElement(defPath, gen, currRow.getSubRows(), child, all, profiles, showMissing, profileBaseFileName, isExtension, snapshot, corePath, imagePath, false, logicalModel, isConstraintMode, allInvariants, currRow, mustSupport); Row childRow = chooseChildRowByGroup(gen, currRow, groups, child, element, isConstraintMode);
if (logicalModel || !child.getPath().endsWith(".id") || (child.getPath().endsWith(".id") && (profile != null) && (profile.getDerivation() == TypeDerivationRule.CONSTRAINT))) {
currRow = genElement(defPath, gen, childRow.getSubRows(), child, all, profiles, showMissing, profileBaseFileName, isExtension, snapshot, corePath, imagePath, false, logicalModel, isConstraintMode, allInvariants, currRow, mustSupport);
}
} }
// if (!snapshot && (extensions == null || !extensions)) // if (!snapshot && (extensions == null || !extensions))
// for (ElementDefinition child : children) // for (ElementDefinition child : children)
@ -3639,6 +3753,34 @@ public class ProfileUtilities extends TranslatingUtilities {
return slicingRow; return slicingRow;
} }
private Row chooseChildRowByGroup(HierarchicalTableGenerator gen, Row row, List<ElementChoiceGroup> groups, ElementDefinition element, ElementDefinition parent, boolean isConstraintMode) {
String name = tail(element.getPath());
for (ElementChoiceGroup grp : groups) {
if (grp.getElements().contains(name)) {
if (grp.getRow() == null) {
grp.setRow(makeChoiceElementRow(gen, row, grp, parent, isConstraintMode));
}
return grp.getRow();
}
}
return row;
}
private Row makeChoiceElementRow(HierarchicalTableGenerator gen, Row prow, ElementChoiceGroup grp, ElementDefinition parent, boolean isConstraintMode) {
Row row = gen.new Row();
row.setAnchor(parent.getPath()+"-"+grp.getName());
row.setColor(getRowColor(parent, isConstraintMode));
row.setLineColor(1);
row.setIcon("icon_choice.gif", HierarchicalTableGenerator.TEXT_ICON_CHOICE);
row.getCells().add(gen.new Cell(null, null, "(Choice of one)", "", null));
row.getCells().add(gen.new Cell());
row.getCells().add(gen.new Cell(null, null, (grp.mandatory ? "1" : "0")+"..1", "", null));
row.getCells().add(gen.new Cell());
row.getCells().add(gen.new Cell());
prow.getSubRows().add(row);
return row;
}
public Cell genElementNameCell(HierarchicalTableGenerator gen, ElementDefinition element, String profileBaseFileName, boolean snapshot, String corePath, public Cell genElementNameCell(HierarchicalTableGenerator gen, ElementDefinition element, String profileBaseFileName, boolean snapshot, String corePath,
String imagePath, boolean root, boolean logicalModel, boolean allInvariants, StructureDefinition profile, Row typesRow, Row row, boolean hasDef, String imagePath, boolean root, boolean logicalModel, boolean allInvariants, StructureDefinition profile, Row typesRow, Row row, boolean hasDef,
boolean ext, UnusedTracker used, String ref, String sName) throws IOException { boolean ext, UnusedTracker used, String ref, String sName) throws IOException {
@ -3985,7 +4127,7 @@ public class ProfileUtilities extends TranslatingUtilities {
} }
if (root) { if (root) {
if (profile.getAbstract()) { if (profile.getAbstract()) {
if (!c.getPieces().isEmpty()) c.addPiece(gen.new Piece("br")); if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); }
c.addPiece(gen.new Piece(null, "This is an abstract profile", null)); c.addPiece(gen.new Piece(null, "This is an abstract profile", null));
} }
} }
@ -3993,10 +4135,10 @@ public class ProfileUtilities extends TranslatingUtilities {
c.getPieces().add(checkForNoChange(definition.getFixed(), gen.new Piece(null, "\""+buildJson(definition.getFixed())+"\"", null).addStyle("color: darkgreen"))); c.getPieces().add(checkForNoChange(definition.getFixed(), gen.new Piece(null, "\""+buildJson(definition.getFixed())+"\"", null).addStyle("color: darkgreen")));
} else { } else {
if (definition != null && definition.hasShort()) { if (definition != null && definition.hasShort()) {
if (!c.getPieces().isEmpty()) c.addPiece(gen.new Piece("br")); if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); }
c.addPiece(checkForNoChange(definition.getShortElement(), gen.new Piece(null, gt(definition.getShortElement()), null))); c.addPiece(checkForNoChange(definition.getShortElement(), gen.new Piece(null, gt(definition.getShortElement()), null)));
} else if (fallback != null && fallback.hasShort()) { } else if (fallback != null && fallback.hasShort()) {
if (!c.getPieces().isEmpty()) c.addPiece(gen.new Piece("br")); if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); }
c.addPiece(gen.new Piece(null, gt(fallback.getShortElement()), null).addStyle("opacity: 0.5")); c.addPiece(gen.new Piece(null, gt(fallback.getShortElement()), null).addStyle("opacity: 0.5"));
} }
if (url != null) { if (url != null) {
@ -4041,7 +4183,7 @@ public class ProfileUtilities extends TranslatingUtilities {
} }
if (definition.hasSlicing()) { if (definition.hasSlicing()) {
if (!c.getPieces().isEmpty()) c.addPiece(gen.new Piece("br")); if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); }
c.getPieces().add(gen.new Piece(null, translate("sd.table", "Slice")+": ", null).addStyle("font-weight:bold")); c.getPieces().add(gen.new Piece(null, translate("sd.table", "Slice")+": ", null).addStyle("font-weight:bold"));
c.getPieces().add(gen.new Piece(null, describeSlice(definition.getSlicing()), null)); c.getPieces().add(gen.new Piece(null, describeSlice(definition.getSlicing()), null));
} }
@ -4095,7 +4237,7 @@ public class ProfileUtilities extends TranslatingUtilities {
} }
if (definition.hasFixed()) { if (definition.hasFixed()) {
if (!c.getPieces().isEmpty()) c.addPiece(gen.new Piece("br")); if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); }
c.getPieces().add(checkForNoChange(definition.getFixed(), gen.new Piece(null, translate("sd.table", "Fixed Value")+": ", null).addStyle("font-weight:bold"))); c.getPieces().add(checkForNoChange(definition.getFixed(), gen.new Piece(null, translate("sd.table", "Fixed Value")+": ", null).addStyle("font-weight:bold")));
if (!useTableForFixedValues || definition.getFixed().isPrimitive()) { if (!useTableForFixedValues || definition.getFixed().isPrimitive()) {
String s = buildJson(definition.getFixed()); String s = buildJson(definition.getFixed());
@ -4113,7 +4255,7 @@ public class ProfileUtilities extends TranslatingUtilities {
c.getPieces().add(p); c.getPieces().add(p);
} }
} else if (definition.hasPattern()) { } else if (definition.hasPattern()) {
if (!c.getPieces().isEmpty()) c.addPiece(gen.new Piece("br")); if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); }
c.getPieces().add(checkForNoChange(definition.getPattern(), gen.new Piece(null, translate("sd.table", "Required Pattern")+": ", null).addStyle("font-weight:bold"))); c.getPieces().add(checkForNoChange(definition.getPattern(), gen.new Piece(null, translate("sd.table", "Required Pattern")+": ", null).addStyle("font-weight:bold")));
if (!useTableForFixedValues || definition.getPattern().isPrimitive()) if (!useTableForFixedValues || definition.getPattern().isPrimitive())
c.getPieces().add(checkForNoChange(definition.getPattern(), gen.new Piece(null, buildJson(definition.getPattern()), null).addStyle("color: darkgreen"))); c.getPieces().add(checkForNoChange(definition.getPattern(), gen.new Piece(null, buildJson(definition.getPattern()), null).addStyle("color: darkgreen")));
@ -4123,13 +4265,13 @@ public class ProfileUtilities extends TranslatingUtilities {
} }
} else if (definition.hasExample()) { } else if (definition.hasExample()) {
for (ElementDefinitionExampleComponent ex : definition.getExample()) { for (ElementDefinitionExampleComponent ex : definition.getExample()) {
if (!c.getPieces().isEmpty()) c.addPiece(gen.new Piece("br")); if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); }
c.getPieces().add(checkForNoChange(ex, gen.new Piece(null, translate("sd.table", "Example")+("".equals("General")? "" : " "+ex.getLabel())+": ", null).addStyle("font-weight:bold"))); c.getPieces().add(checkForNoChange(ex, gen.new Piece(null, translate("sd.table", "Example")+("".equals("General")? "" : " "+ex.getLabel())+": ", null).addStyle("font-weight:bold")));
c.getPieces().add(checkForNoChange(ex, gen.new Piece(null, buildJson(ex.getValue()), null).addStyle("color: darkgreen"))); c.getPieces().add(checkForNoChange(ex, gen.new Piece(null, buildJson(ex.getValue()), null).addStyle("color: darkgreen")));
} }
} }
if (definition.hasMaxLength() && definition.getMaxLength()!=0) { if (definition.hasMaxLength() && definition.getMaxLength()!=0) {
if (!c.getPieces().isEmpty()) c.addPiece(gen.new Piece("br")); if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); }
c.getPieces().add(checkForNoChange(definition.getMaxLengthElement(), gen.new Piece(null, "Max Length: ", null).addStyle("font-weight:bold"))); c.getPieces().add(checkForNoChange(definition.getMaxLengthElement(), gen.new Piece(null, "Max Length: ", null).addStyle("font-weight:bold")));
c.getPieces().add(checkForNoChange(definition.getMaxLengthElement(), gen.new Piece(null, Integer.toString(definition.getMaxLength()), null).addStyle("color: darkgreen"))); c.getPieces().add(checkForNoChange(definition.getMaxLengthElement(), gen.new Piece(null, Integer.toString(definition.getMaxLength()), null).addStyle("color: darkgreen")));
} }
@ -4367,7 +4509,7 @@ public class ProfileUtilities extends TranslatingUtilities {
} }
if (definition.hasSlicing()) { if (definition.hasSlicing()) {
if (!c.getPieces().isEmpty()) c.addPiece(gen.new Piece("br")); if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); }
c.getPieces().add(gen.new Piece(null, "Slice: ", null).addStyle("font-weight:bold")); c.getPieces().add(gen.new Piece(null, "Slice: ", null).addStyle("font-weight:bold"));
c.getPieces().add(gen.new Piece(null, describeSlice(definition.getSlicing()), null)); c.getPieces().add(gen.new Piece(null, describeSlice(definition.getSlicing()), null));
} }
@ -4389,12 +4531,16 @@ public class ProfileUtilities extends TranslatingUtilities {
} }
} }
for (ElementDefinitionConstraintComponent inv : definition.getConstraint()) { for (ElementDefinitionConstraintComponent inv : definition.getConstraint()) {
if (!c.getPieces().isEmpty()) c.addPiece(gen.new Piece("br")); if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); }
c.getPieces().add(checkForNoChange(inv, gen.new Piece(null, inv.getKey()+": ", null).addStyle("font-weight:bold"))); c.getPieces().add(checkForNoChange(inv, gen.new Piece(null, inv.getKey()+": ", null).addStyle("font-weight:bold")));
c.getPieces().add(checkForNoChange(inv, gen.new Piece(null, inv.getHuman(), null))); if (inv.getHumanElement().hasExtension("http://hl7.org/fhir/StructureDefinition/rendering-markdown")) {
c.addMarkdown(inv.getHumanElement().getExtensionString("http://hl7.org/fhir/StructureDefinition/rendering-markdown"));
} else {
c.getPieces().add(checkForNoChange(inv, gen.new Piece(null, inv.getHuman(), null)));
}
} }
if (definition.hasFixed()) { if (definition.hasFixed()) {
if (!c.getPieces().isEmpty()) c.addPiece(gen.new Piece("br")); if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); }
c.getPieces().add(checkForNoChange(definition.getFixed(), gen.new Piece(null, "Fixed Value: ", null).addStyle("font-weight:bold"))); c.getPieces().add(checkForNoChange(definition.getFixed(), gen.new Piece(null, "Fixed Value: ", null).addStyle("font-weight:bold")));
String s = buildJson(definition.getFixed()); String s = buildJson(definition.getFixed());
String link = null; String link = null;
@ -4402,18 +4548,18 @@ public class ProfileUtilities extends TranslatingUtilities {
link = pkp.getLinkForUrl(corePath, s); link = pkp.getLinkForUrl(corePath, s);
c.getPieces().add(checkForNoChange(definition.getFixed(), gen.new Piece(link, s, null).addStyle("color: darkgreen"))); c.getPieces().add(checkForNoChange(definition.getFixed(), gen.new Piece(link, s, null).addStyle("color: darkgreen")));
} else if (definition.hasPattern()) { } else if (definition.hasPattern()) {
if (!c.getPieces().isEmpty()) c.addPiece(gen.new Piece("br")); if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); }
c.getPieces().add(checkForNoChange(definition.getPattern(), gen.new Piece(null, "Required Pattern: ", null).addStyle("font-weight:bold"))); c.getPieces().add(checkForNoChange(definition.getPattern(), gen.new Piece(null, "Required Pattern: ", null).addStyle("font-weight:bold")));
c.getPieces().add(checkForNoChange(definition.getPattern(), gen.new Piece(null, buildJson(definition.getPattern()), null).addStyle("color: darkgreen"))); c.getPieces().add(checkForNoChange(definition.getPattern(), gen.new Piece(null, buildJson(definition.getPattern()), null).addStyle("color: darkgreen")));
} else if (definition.hasExample()) { } else if (definition.hasExample()) {
for (ElementDefinitionExampleComponent ex : definition.getExample()) { for (ElementDefinitionExampleComponent ex : definition.getExample()) {
if (!c.getPieces().isEmpty()) c.addPiece(gen.new Piece("br")); if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); }
c.getPieces().add(checkForNoChange(ex, gen.new Piece(null, "Example'"+("".equals("General")? "" : " "+ex.getLabel()+"'")+": ", null).addStyle("font-weight:bold"))); c.getPieces().add(checkForNoChange(ex, gen.new Piece(null, "Example'"+("".equals("General")? "" : " "+ex.getLabel()+"'")+": ", null).addStyle("font-weight:bold")));
c.getPieces().add(checkForNoChange(ex, gen.new Piece(null, buildJson(ex.getValue()), null).addStyle("color: darkgreen"))); c.getPieces().add(checkForNoChange(ex, gen.new Piece(null, buildJson(ex.getValue()), null).addStyle("color: darkgreen")));
} }
} }
if (definition.hasMaxLength() && definition.getMaxLength()!=0) { if (definition.hasMaxLength() && definition.getMaxLength()!=0) {
if (!c.getPieces().isEmpty()) c.addPiece(gen.new Piece("br")); if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); }
c.getPieces().add(checkForNoChange(definition.getMaxLengthElement(), gen.new Piece(null, "Max Length: ", null).addStyle("font-weight:bold"))); c.getPieces().add(checkForNoChange(definition.getMaxLengthElement(), gen.new Piece(null, "Max Length: ", null).addStyle("font-weight:bold")));
c.getPieces().add(checkForNoChange(definition.getMaxLengthElement(), gen.new Piece(null, Integer.toString(definition.getMaxLength()), null).addStyle("color: darkgreen"))); c.getPieces().add(checkForNoChange(definition.getMaxLengthElement(), gen.new Piece(null, Integer.toString(definition.getMaxLength()), null).addStyle("color: darkgreen")));
} }
@ -4434,14 +4580,14 @@ public class ProfileUtilities extends TranslatingUtilities {
} }
} }
if (definition.hasDefinition()) { if (definition.hasDefinition()) {
if (!c.getPieces().isEmpty()) c.addPiece(gen.new Piece("br")); if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); }
c.getPieces().add(gen.new Piece(null, "Definition: ", null).addStyle("font-weight:bold")); c.getPieces().add(gen.new Piece(null, "Definition: ", null).addStyle("font-weight:bold"));
c.addPiece(gen.new Piece("br")); c.addPiece(gen.new Piece("br"));
c.addMarkdown(definition.getDefinition()); c.addMarkdown(definition.getDefinition());
// c.getPieces().add(checkForNoChange(definition.getCommentElement(), gen.new Piece(null, definition.getComment(), null))); // c.getPieces().add(checkForNoChange(definition.getCommentElement(), gen.new Piece(null, definition.getComment(), null)));
} }
if (definition.getComment()!=null) { if (definition.getComment()!=null) {
if (!c.getPieces().isEmpty()) c.addPiece(gen.new Piece("br")); if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); }
c.getPieces().add(gen.new Piece(null, "Comments: ", null).addStyle("font-weight:bold")); c.getPieces().add(gen.new Piece(null, "Comments: ", null).addStyle("font-weight:bold"));
c.addPiece(gen.new Piece("br")); c.addPiece(gen.new Piece("br"));
c.addMarkdown(definition.getComment()); c.addMarkdown(definition.getComment());
@ -5935,6 +6081,64 @@ public class ProfileUtilities extends TranslatingUtilities {
} }
public List<ElementChoiceGroup> readChoices(ElementDefinition ed, List<ElementDefinition> children) {
List<ElementChoiceGroup> result = new ArrayList<>();
for (ElementDefinitionConstraintComponent c : ed.getConstraint()) {
ElementChoiceGroup grp = processConstraint(children, c);
if (grp != null) {
result.add(grp);
}
}
return result;
}
private ElementChoiceGroup processConstraint(List<ElementDefinition> children, ElementDefinitionConstraintComponent c) {
if (!c.hasExpression()) {
return null;
}
ExpressionNode expr = fpe.parse(c.getExpression());
if (expr.getKind() != Kind.Group || expr.getOpNext() == null || !(expr.getOperation() == Operation.Equals || expr.getOperation() == Operation.LessOrEqual)) {
return null;
}
ExpressionNode n1 = expr.getGroup();
ExpressionNode n2 = expr.getOpNext();
if (n2.getKind() != Kind.Constant || n2.getInner() != null || n2.getOpNext() != null || !"1".equals(n2.getConstant().primitiveValue())) {
return null;
}
ElementChoiceGroup grp = new ElementChoiceGroup(c.getKey(), expr.getOperation() == Operation.Equals);
while (n1 != null) {
if (n1.getKind() != Kind.Name || n1.getInner() != null) {
return null;
}
grp.elements.add(n1.getName());
if (n1.getOperation() == null || n1.getOperation() == Operation.Union) {
n1 = n1.getOpNext();
} else {
return null;
}
}
int total = 0;
for (String n : grp.elements) {
boolean found = false;
for (ElementDefinition child : children) {
String name = tail(child.getPath());
if (n.equals(name)) {
found = true;
if (!"0".equals(child.getMax())) {
total++;
}
}
}
if (!found) {
return null;
}
}
if (total <= 1) {
return null;
}
return grp;
}
} }

View File

@ -171,8 +171,9 @@ private Map<String, Object> userData;
List<Property> children = new ArrayList<Property>(); List<Property> children = new ArrayList<Property>();
listChildren(children); listChildren(children);
for (Property c : children) for (Property c : children)
if (c.getName().equals(name)) if (c.getName().equals(name) || c.getName().equals(name+"[x]")) {
return c; return c;
}
return null; return null;
} }

View File

@ -14,10 +14,16 @@ import org.hl7.fhir.r5.model.Annotation;
import org.hl7.fhir.r5.model.Base; import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.BaseDateTimeType; import org.hl7.fhir.r5.model.BaseDateTimeType;
import org.hl7.fhir.r5.model.CanonicalResource; import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.CanonicalType;
import org.hl7.fhir.r5.model.CodeSystem; import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.CodeableConcept; import org.hl7.fhir.r5.model.CodeableConcept;
import org.hl7.fhir.r5.model.Coding; import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.ContactPoint; import org.hl7.fhir.r5.model.ContactPoint;
import org.hl7.fhir.r5.model.DataRequirement;
import org.hl7.fhir.r5.model.DataRequirement.DataRequirementCodeFilterComponent;
import org.hl7.fhir.r5.model.DataRequirement.DataRequirementDateFilterComponent;
import org.hl7.fhir.r5.model.DataRequirement.DataRequirementSortComponent;
import org.hl7.fhir.r5.model.DataRequirement.SortDirection;
import org.hl7.fhir.r5.model.ContactPoint.ContactPointSystem; import org.hl7.fhir.r5.model.ContactPoint.ContactPointSystem;
import org.hl7.fhir.r5.model.DataType; import org.hl7.fhir.r5.model.DataType;
import org.hl7.fhir.r5.model.DateTimeType; import org.hl7.fhir.r5.model.DateTimeType;
@ -778,6 +784,102 @@ public class DataRenderer extends Renderer {
x.addText(!p.hasEnd() ? "(ongoing)" : p.getEndElement().toHumanDisplay()); x.addText(!p.hasEnd() ? "(ongoing)" : p.getEndElement().toHumanDisplay());
} }
public void renderDataRequirement(XhtmlNode x, DataRequirement dr) {
XhtmlNode tbl = x.table("grid");
XhtmlNode tr = tbl.tr();
XhtmlNode td = tr.td().colspan("2");
td.b().tx("Type");
td.tx(": ");
StructureDefinition sd = context.getWorker().fetchTypeDefinition(dr.getType().toCode());
if (sd != null && sd.hasUserData("path")) {
td.ah(sd.getUserString("path")).tx(dr.getType().toCode());
} else {
td.tx(dr.getType().toCode());
}
if (dr.hasProfile()) {
td.tx(" (");
boolean first = true;
for (CanonicalType p : dr.getProfile()) {
if (first) first = false; else td.tx(" | ");
sd = context.getWorker().fetchResource(StructureDefinition.class, p.getValue());
if (sd != null && sd.hasUserData("path")) {
td.ah(sd.getUserString("path")).tx(sd.present());
} else {
td.tx(p.asStringValue());
}
}
td.tx(")");
}
if (dr.hasSubject()) {
tr = tbl.tr();
td = tr.td().colspan("2");
td.b().tx("Subject");
if (dr.hasSubjectReference()) {
renderReference(td, dr.getSubjectReference());
} else {
renderCodeableConcept(td, dr.getSubjectCodeableConcept());
}
}
if (dr.hasCodeFilter() || dr.hasDateFilter()) {
tr = tbl.tr().backgroundColor("#efefef");
tr.td().tx("Filter");
tr.td().tx("Value");
}
for (DataRequirementCodeFilterComponent cf : dr.getCodeFilter()) {
tr = tbl.tr();
if (cf.hasPath()) {
tr.td().tx(cf.getPath());
} else {
tr.td().tx("Search on " +cf.getSearchParam());
}
if (cf.hasValueSet()) {
td = tr.td();
td.tx("In ValueSet ");
render(td, cf.getValueSetElement());
} else {
boolean first = true;
td = tr.td();
td.tx("One of these codes: ");
for (Coding c : cf.getCode()) {
if (first) first = false; else td.tx(", ");
render(td, c);
}
}
}
for (DataRequirementDateFilterComponent cf : dr.getDateFilter()) {
tr = tbl.tr();
if (cf.hasPath()) {
tr.td().tx(cf.getPath());
} else {
tr.td().tx("Search on " +cf.getSearchParam());
}
render(tr.td(), cf.getValue());
}
if (dr.hasSort() || dr.hasLimit()) {
tr = tbl.tr();
td = tr.td().colspan("2");
if (dr.hasLimit()) {
td.b().tx("Limit");
td.tx(": ");
td.tx(dr.getLimit());
if (dr.hasSort()) {
td.tx(", ");
}
}
if (dr.hasSort()) {
td.b().tx("Sort");
td.tx(": ");
boolean first = true;
for (DataRequirementSortComponent p : dr.getSort()) {
if (first) first = false; else td.tx(" | ");
td.tx(p.getDirection() == SortDirection.ASCENDING ? "+" : "-");
td.tx(p.getPath());
}
}
}
}
private String displayTiming(Timing s) throws FHIRException { private String displayTiming(Timing s) throws FHIRException {
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
if (s.hasCode()) if (s.hasCode())

View File

@ -31,13 +31,19 @@ import org.hl7.fhir.utilities.xhtml.XhtmlNode;
public class ParametersRenderer extends ResourceRenderer { public class ParametersRenderer extends ResourceRenderer {
public ParametersRenderer(RenderingContext context) {
super(context);
}
public ParametersRenderer(RenderingContext context, ResourceContext rcontext) { public ParametersRenderer(RenderingContext context, ResourceContext rcontext) {
super(context, rcontext); super(context, rcontext);
} }
@Override @Override
public boolean render(XhtmlNode x, Resource r) throws FHIRFormatError, DefinitionException, IOException, FHIRException, EOperationOutcome { public boolean render(XhtmlNode x, Resource r) throws FHIRFormatError, DefinitionException, IOException, FHIRException, EOperationOutcome {
x.h2().tx("Parameters");
XhtmlNode tbl = x.table("grid");
params(tbl, ((Parameters) r).getParameter(), 0);
return false; return false;
} }
@ -87,7 +93,7 @@ public class ParametersRenderer extends ResourceRenderer {
} }
} else if (p.has("part")) { } else if (p.has("part")) {
tr.td(); tr.td();
PropertyWrapper pw = getProperty(p, "parameter"); PropertyWrapper pw = getProperty(p, "part");
paramsW(tbl, pw.getValues(), 1); paramsW(tbl, pw.getValues(), 1);
} }
} }

View File

@ -27,6 +27,7 @@ import org.hl7.fhir.r5.model.CodeableReference;
import org.hl7.fhir.r5.model.Coding; import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.ContactDetail; import org.hl7.fhir.r5.model.ContactDetail;
import org.hl7.fhir.r5.model.ContactPoint; import org.hl7.fhir.r5.model.ContactPoint;
import org.hl7.fhir.r5.model.DataRequirement;
import org.hl7.fhir.r5.model.DateTimeType; import org.hl7.fhir.r5.model.DateTimeType;
import org.hl7.fhir.r5.model.DomainResource; import org.hl7.fhir.r5.model.DomainResource;
import org.hl7.fhir.r5.model.Dosage; import org.hl7.fhir.r5.model.Dosage;
@ -82,6 +83,7 @@ import org.w3c.dom.Element;
public class ProfileDrivenRenderer extends ResourceRenderer { public class ProfileDrivenRenderer extends ResourceRenderer {
private Set<String> containedIds = new HashSet<>(); private Set<String> containedIds = new HashSet<>();
private boolean hasExtensions;
public ProfileDrivenRenderer(RenderingContext context, ResourceContext rcontext) { public ProfileDrivenRenderer(RenderingContext context, ResourceContext rcontext) {
super(context, rcontext); super(context, rcontext);
@ -108,12 +110,13 @@ public class ProfileDrivenRenderer extends ResourceRenderer {
System.out.println("hah!"); System.out.println("hah!");
} }
containedIds.clear(); containedIds.clear();
hasExtensions = false;
generateByProfile(r, sd, r.root(), sd.getSnapshot().getElement(), ed, context.getProfileUtilities().getChildList(sd, ed), x, r.fhirType(), false, 0); generateByProfile(r, sd, r.root(), sd.getSnapshot().getElement(), ed, context.getProfileUtilities().getChildList(sd, ed), x, r.fhirType(), false, 0);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
x.para().b().style("color: maroon").tx("Exception generating Narrative: "+e.getMessage()); x.para().b().style("color: maroon").tx("Exception generating Narrative: "+e.getMessage());
} }
return false; return hasExtensions;
} }
@Override @Override
@ -378,6 +381,9 @@ public class ProfileDrivenRenderer extends ResourceRenderer {
} }
} else if (e instanceof Resource) { } else if (e instanceof Resource) {
return; return;
} else if (e instanceof DataRequirement) {
DataRequirement p = (DataRequirement) e;
renderDataRequirement(x, p);
} else if (e instanceof ElementDefinition) { } else if (e instanceof ElementDefinition) {
x.tx("todo-bundle"); x.tx("todo-bundle");
} else if (e != null && !(e instanceof Attachment) && !(e instanceof Narrative) && !(e instanceof Meta)) { } else if (e != null && !(e instanceof Attachment) && !(e instanceof Narrative) && !(e instanceof Meta)) {
@ -386,7 +392,7 @@ public class ProfileDrivenRenderer extends ResourceRenderer {
throw new NotImplementedException("type "+e.getClass().getName()+" not handled yet, and no structure found"); throw new NotImplementedException("type "+e.getClass().getName()+" not handled yet, and no structure found");
else else
generateByProfile(res, sd, ew, sd.getSnapshot().getElement(), sd.getSnapshot().getElementFirstRep(), generateByProfile(res, sd, ew, sd.getSnapshot().getElement(), sd.getSnapshot().getElementFirstRep(),
getChildrenForPath(sd.getSnapshot().getElement(), sd.getSnapshot().getElementFirstRep().getPath()), x, path, showCodeDetails, indent + 1); getChildrenForPath(sd.getSnapshot().getElement(), sd.getSnapshot().getElementFirstRep().getPath()), x, e.fhirType(), showCodeDetails, indent + 1);
} }
} }
@ -612,65 +618,98 @@ public class ProfileDrivenRenderer extends ResourceRenderer {
for (PropertyWrapper p : splitExtensions(profile, e.children())) { for (PropertyWrapper p : splitExtensions(profile, e.children())) {
if (p.hasValues()) { if (p.hasValues()) {
ElementDefinition child = getElementDefinition(children, path+"."+p.getName(), p); ElementDefinition child = getElementDefinition(children, path+"."+p.getName(), p);
if (child == null) {
child = p.getElementDefinition();
}
if (child != null) { if (child != null) {
Map<String, String> displayHints = readDisplayHints(child); generateElementByProfile(res, profile, allElements, x, path, showCodeDetails, indent, p, child);
if ("DomainResource.contained".equals(child.getBase().getPath())) { }
}
}
}
}
public void generateElementByProfile(ResourceWrapper res, StructureDefinition profile, List<ElementDefinition> allElements, XhtmlNode x, String path,
boolean showCodeDetails, int indent, PropertyWrapper p, ElementDefinition child) throws UnsupportedEncodingException, IOException, EOperationOutcome {
Map<String, String> displayHints = readDisplayHints(child);
if ("DomainResource.contained".equals(child.getBase().getPath())) {
// if (p.getValues().size() > 0 && child != null) { // if (p.getValues().size() > 0 && child != null) {
// for (BaseWrapper v : p.getValues()) { // for (BaseWrapper v : p.getValues()) {
// x.an(v.get("id").primitiveValue()); // x.an(v.get("id").primitiveValue());
// } // }
// } // }
} else if (!exemptFromRendering(child)) { } else if (!exemptFromRendering(child)) {
List<ElementDefinition> grandChildren = getChildrenForPath(allElements, path+"."+p.getName()); if (isExtension(p)) {
filterGrandChildren(grandChildren, path+"."+p.getName(), p); hasExtensions = true;
if (p.getValues().size() > 0) { }
if (isPrimitive(child)) { List<ElementDefinition> grandChildren = getChildrenForPath(allElements, path+"."+p.getName());
XhtmlNode para = x.para(); filterGrandChildren(grandChildren, path+"."+p.getName(), p);
String name = p.getName(); if (p.getValues().size() > 0) {
if (name.endsWith("[x]")) if (isPrimitive(child)) {
name = name.substring(0, name.length() - 3); XhtmlNode para = x.para();
if (showCodeDetails || !isDefaultValue(displayHints, p.getValues())) { String name = p.getName();
para.b().addText(name); if (name.endsWith("[x]"))
para.tx(": "); name = name.substring(0, name.length() - 3);
if (renderAsList(child) && p.getValues().size() > 1) { if (showCodeDetails || !isDefaultValue(displayHints, p.getValues())) {
XhtmlNode list = x.ul(); para.b().addText(name);
for (BaseWrapper v : p.getValues()) para.tx(": ");
renderLeaf(res, v, child, x, list.li(), false, showCodeDetails, displayHints, path, indent); if (renderAsList(child) && p.getValues().size() > 1) {
} else { XhtmlNode list = x.ul();
boolean first = true; for (BaseWrapper v : p.getValues())
for (BaseWrapper v : p.getValues()) { renderLeaf(res, v, child, x, list.li(), false, showCodeDetails, displayHints, path, indent);
if (first) } else {
first = false; boolean first = true;
else for (BaseWrapper v : p.getValues()) {
para.tx(", "); if (first)
renderLeaf(res, v, child, x, para, false, showCodeDetails, displayHints, path, indent); first = false;
} else
} para.tx(", ");
} renderLeaf(res, v, child, x, para, false, showCodeDetails, displayHints, path, indent);
} else if (canDoTable(path, p, grandChildren)) { }
x.addTag(getHeader()).addText(Utilities.capitalize(Utilities.camelCase(Utilities.pluralizeMe(p.getName())))); }
XhtmlNode tbl = x.table( "grid"); }
XhtmlNode tr = tbl.tr(); } else if (canDoTable(path, p, grandChildren)) {
tr.td().tx("-"); // work around problem with empty table rows x.addTag(getHeader()).addText(Utilities.capitalize(Utilities.camelCase(Utilities.pluralizeMe(p.getName()))));
addColumnHeadings(tr, grandChildren); XhtmlNode tbl = x.table( "grid");
for (BaseWrapper v : p.getValues()) { XhtmlNode tr = tbl.tr();
if (v != null) { tr.td().tx("-"); // work around problem with empty table rows
tr = tbl.tr(); addColumnHeadings(tr, grandChildren);
tr.td().tx("*"); // work around problem with empty table rows for (BaseWrapper v : p.getValues()) {
addColumnValues(res, tr, grandChildren, v, showCodeDetails, displayHints, path, indent); if (v != null) {
} tr = tbl.tr();
} tr.td().tx("*"); // work around problem with empty table rows
} else { addColumnValues(res, tr, grandChildren, v, showCodeDetails, displayHints, path, indent);
for (BaseWrapper v : p.getValues()) { }
if (v != null) { }
XhtmlNode bq = x.addTag("blockquote"); } else if (isExtension(p)) {
bq.para().b().addText(p.getName()); for (BaseWrapper v : p.getValues()) {
generateByProfile(res, profile, v, allElements, child, grandChildren, bq, path+"."+p.getName(), showCodeDetails, indent+1); if (v != null) {
} PropertyWrapper vp = v.getChildByName("value");
} PropertyWrapper ev = v.getChildByName("extension");
if (vp.hasValues()) {
BaseWrapper vv = vp.value();
XhtmlNode para = x.para();
para.b().addText(p.getStructure().present());
para.tx(": ");
renderLeaf(res, v, child, x, para, false, showCodeDetails, displayHints, path, indent);
} else if (ev.hasValues()) {
XhtmlNode bq = x.addTag("blockquote");
bq.para().b().addText(isExtension(p) ? p.getStructure().present() : p.getName());
for (BaseWrapper vv : ev.getValues()) {
StructureDefinition ex = context.getWorker().fetchTypeDefinition("Extension");
List<ElementDefinition> children = getChildrenForPath(ex.getSnapshot().getElement(), "Extension");
generateByProfile(res, ex, vv, allElements, child, children, bq, "Extension", showCodeDetails, indent+1);
} }
} }
} }
}
} else {
for (BaseWrapper v : p.getValues()) {
if (v != null) {
XhtmlNode bq = x.addTag("blockquote");
bq.para().b().addText(isExtension(p) ? p.getStructure().present() : p.getName());
generateByProfile(res, profile, v, allElements, child, grandChildren, bq, path+"."+p.getName(), showCodeDetails, indent+1);
}
} }
} }
} }
@ -699,6 +738,9 @@ public class ProfileDrivenRenderer extends ResourceRenderer {
} }
private boolean canDoTable(String path, PropertyWrapper p, List<ElementDefinition> grandChildren) { private boolean canDoTable(String path, PropertyWrapper p, List<ElementDefinition> grandChildren) {
if (isExtension(p)) {
return false;
}
for (ElementDefinition e : grandChildren) { for (ElementDefinition e : grandChildren) {
List<PropertyWrapper> values = getValues(path, p, e); List<PropertyWrapper> values = getValues(path, p, e);
if (values.size() > 1 || !isPrimitive(e) || !canCollapse(e)) if (values.size() > 1 || !isPrimitive(e) || !canCollapse(e))
@ -707,6 +749,10 @@ public class ProfileDrivenRenderer extends ResourceRenderer {
return true; return true;
} }
public boolean isExtension(PropertyWrapper p) {
return p.getName().contains("extension[");
}
private boolean canCollapse(ElementDefinition e) { private boolean canCollapse(ElementDefinition e) {
// we can collapse any data type // we can collapse any data type
@ -792,10 +838,10 @@ public class ProfileDrivenRenderer extends ResourceRenderer {
if (url.startsWith("http://hl7.org/fhir") && !url.startsWith("http://hl7.org/fhir/us")) if (url.startsWith("http://hl7.org/fhir") && !url.startsWith("http://hl7.org/fhir/us"))
throw new DefinitionException("unknown extension "+url); throw new DefinitionException("unknown extension "+url);
// System.out.println("unknown extension "+url); // System.out.println("unknown extension "+url);
pe = new PropertyWrapperDirect(this.context, new Property(p.getName()+"["+url+"]", p.getTypeCode(), p.getDefinition(), p.getMinCardinality(), p.getMaxCardinality(), ex)); pe = new PropertyWrapperDirect(this.context, new Property(p.getName()+"["+url+"]", p.getTypeCode(), p.getDefinition(), p.getMinCardinality(), p.getMaxCardinality(), ex), ed.getSnapshot().getElementFirstRep());
} else { } else {
ElementDefinition def = ed.getSnapshot().getElement().get(0); ElementDefinition def = ed.getSnapshot().getElement().get(0);
pe = new PropertyWrapperDirect(this.context, new Property(p.getName()+"["+url+"]", "Extension", def.getDefinition(), def.getMin(), def.getMax().equals("*") ? Integer.MAX_VALUE : Integer.parseInt(def.getMax()), ex)); pe = new PropertyWrapperDirect(this.context, new Property(p.getName()+"["+url+"]", "Extension", def.getDefinition(), def.getMin(), def.getMax().equals("*") ? Integer.MAX_VALUE : Integer.parseInt(def.getMax()), ex), ed.getSnapshot().getElementFirstRep());
((PropertyWrapperDirect) pe).getWrapped().setStructure(ed); ((PropertyWrapperDirect) pe).getWrapped().setStructure(ed);
} }
results.add(pe); results.add(pe);

View File

@ -72,6 +72,9 @@ public class RendererFactory {
if ("OperationOutcome".equals(resourceName)) { if ("OperationOutcome".equals(resourceName)) {
return new OperationOutcomeRenderer(context); return new OperationOutcomeRenderer(context);
} }
if ("Parameters".equals(resourceName)) {
return new ParametersRenderer(context);
}
return new ProfileDrivenRenderer(context); return new ProfileDrivenRenderer(context);
} }

View File

@ -8,6 +8,7 @@ import java.util.List;
import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError; import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.model.Base; import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.Narrative.NarrativeStatus; import org.hl7.fhir.r5.model.Narrative.NarrativeStatus;
import org.hl7.fhir.r5.renderers.ResourceRenderer; import org.hl7.fhir.r5.renderers.ResourceRenderer;
@ -28,6 +29,7 @@ public class BaseWrappers {
public int getMinCardinality(); public int getMinCardinality();
public int getMaxCardinality(); public int getMaxCardinality();
public StructureDefinition getStructure(); public StructureDefinition getStructure();
public ElementDefinition getElementDefinition();
public BaseWrapper value(); public BaseWrapper value();
public ResourceWrapper getAsResource(); public ResourceWrapper getAsResource();
public String fhirType(); public String fhirType();
@ -87,7 +89,7 @@ public class BaseWrappers {
@Override @Override
public boolean has(String name) { public boolean has(String name) {
for (PropertyWrapper p : children()) { for (PropertyWrapper p : children()) {
if (p.getName().equals(name)) { if (p.getName().equals(name) || p.getName().equals(name+"[x]") ) {
return p.hasValues(); return p.hasValues();
} }
} }
@ -97,7 +99,7 @@ public class BaseWrappers {
@Override @Override
public Base get(String name) throws UnsupportedEncodingException, FHIRException, IOException { public Base get(String name) throws UnsupportedEncodingException, FHIRException, IOException {
for (PropertyWrapper p : children()) { for (PropertyWrapper p : children()) {
if (p.getName().equals(name)) { if (p.getName().equals(name) || p.getName().equals(name+"[x]")) {
if (p.hasValues()) { if (p.hasValues()) {
return p.getValues().get(0).getBase(); return p.getValues().get(0).getBase();
} else { } else {
@ -111,7 +113,7 @@ public class BaseWrappers {
@Override @Override
public List<BaseWrapper> children(String name) throws UnsupportedEncodingException, FHIRException, IOException { public List<BaseWrapper> children(String name) throws UnsupportedEncodingException, FHIRException, IOException {
for (PropertyWrapper p : children()) { for (PropertyWrapper p : children()) {
if (p.getName().equals(name)) { if (p.getName().equals(name) || p.getName().equals(name+"[x]")) {
List<BaseWrapper> res = new ArrayList<>(); List<BaseWrapper> res = new ArrayList<>();
for (BaseWrapper b : p.getValues()) { for (BaseWrapper b : p.getValues()) {
res.add(b); res.add(b);

View File

@ -206,6 +206,11 @@ public class DOMWrappers {
return getTypeCode(); return getTypeCode();
} }
@Override
public ElementDefinition getElementDefinition() {
return definition;
}
} }
public static class ResourceWrapperElement extends WrapperBaseImpl implements ResourceWrapper { public static class ResourceWrapperElement extends WrapperBaseImpl implements ResourceWrapper {

View File

@ -8,6 +8,7 @@ import java.util.List;
import org.hl7.fhir.r5.model.Base; import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.CanonicalResource; import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.DomainResource; import org.hl7.fhir.r5.model.DomainResource;
import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.Encounter; import org.hl7.fhir.r5.model.Encounter;
import org.hl7.fhir.r5.model.Narrative.NarrativeStatus; import org.hl7.fhir.r5.model.Narrative.NarrativeStatus;
import org.hl7.fhir.r5.model.Patient; import org.hl7.fhir.r5.model.Patient;
@ -29,6 +30,7 @@ public class DirectWrappers {
public static class PropertyWrapperDirect extends RendererWrapperImpl implements PropertyWrapper { public static class PropertyWrapperDirect extends RendererWrapperImpl implements PropertyWrapper {
private Property wrapped; private Property wrapped;
private List<BaseWrapper> list; private List<BaseWrapper> list;
private ElementDefinition ed;
public PropertyWrapperDirect(RenderingContext context, Property wrapped) { public PropertyWrapperDirect(RenderingContext context, Property wrapped) {
super(context); super(context);
@ -37,6 +39,14 @@ public class DirectWrappers {
this.wrapped = wrapped; this.wrapped = wrapped;
} }
public PropertyWrapperDirect(RenderingContext context, Property wrapped, ElementDefinition ed) {
super(context);
if (wrapped == null)
throw new Error("wrapped == null");
this.wrapped = wrapped;
this.ed = ed;
}
@Override @Override
public String getName() { public String getName() {
return wrapped.getName(); return wrapped.getName();
@ -106,6 +116,11 @@ public class DirectWrappers {
public String fhirType() { public String fhirType() {
return wrapped.getTypeCode(); return wrapped.getTypeCode();
} }
@Override
public ElementDefinition getElementDefinition() {
return ed;
}
} }
public static class BaseWrapperDirect extends WrapperBaseImpl implements BaseWrapper { public static class BaseWrapperDirect extends WrapperBaseImpl implements BaseWrapper {

View File

@ -58,7 +58,7 @@ public class ElementWrappers {
throw new FHIRException(e.getMessage(), e); throw new FHIRException(e.getMessage(), e);
} }
if (context.getParser() == null) { if (context.getParser() == null) {
System.out.println("Noe version specific parser provided"); System.out.println("No version specific parser provided");
} }
if (context.getParser() == null) { if (context.getParser() == null) {
throw new Error("No type parser provided to renderer context"); throw new Error("No type parser provided to renderer context");
@ -324,6 +324,11 @@ public class ElementWrappers {
return getTypeCode(); return getTypeCode();
} }
@Override
public ElementDefinition getElementDefinition() {
return definition;
}
} }
} }

View File

@ -319,6 +319,20 @@ public class FHIRPathEngine {
} }
} }
public FHIRPathEngine(IWorkerContext worker, ProfileUtilities utilities) {
super();
this.worker = worker;
profileUtilities = utilities;
for (StructureDefinition sd : worker.getStructures()) {
if (sd.getDerivation() == TypeDerivationRule.SPECIALIZATION && sd.getKind() != StructureDefinitionKind.LOGICAL) {
allTypes.put(sd.getName(), sd);
}
if (sd.getDerivation() == TypeDerivationRule.SPECIALIZATION && sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE) {
primitiveTypes.add(sd.getName());
}
}
}
// --- 3 methods to override in children ------------------------------------------------------- // --- 3 methods to override in children -------------------------------------------------------
// if you don't override, it falls through to the using the base reference implementation // if you don't override, it falls through to the using the base reference implementation

View File

@ -104,17 +104,17 @@ public class NPMPackageGenerator {
private NpmPackageIndexBuilder indexer; private NpmPackageIndexBuilder indexer;
public NPMPackageGenerator(String destFile, String canonical, String url, PackageType kind, ImplementationGuide ig, Date date) throws FHIRException, IOException { public NPMPackageGenerator(String destFile, String canonical, String url, PackageType kind, ImplementationGuide ig, Date date, boolean notForPublication) throws FHIRException, IOException {
super(); super();
this.destFile = destFile; this.destFile = destFile;
start(); start();
List<String> fhirVersion = new ArrayList<>(); List<String> fhirVersion = new ArrayList<>();
for (Enumeration<FHIRVersion> v : ig.getFhirVersion()) for (Enumeration<FHIRVersion> v : ig.getFhirVersion())
fhirVersion.add(v.asStringValue()); fhirVersion.add(v.asStringValue());
buildPackageJson(canonical, kind, url, date, ig, fhirVersion); buildPackageJson(canonical, kind, url, date, ig, fhirVersion, notForPublication);
} }
public static NPMPackageGenerator subset(NPMPackageGenerator master, String destFile, String id, String name, Date date) throws FHIRException, IOException { public static NPMPackageGenerator subset(NPMPackageGenerator master, String destFile, String id, String name, Date date, boolean notForPublication) throws FHIRException, IOException {
JsonObject p = master.packageJ.deepCopy(); JsonObject p = master.packageJ.deepCopy();
p.remove("name"); p.remove("name");
p.addProperty("name", id); p.addProperty("name", id);
@ -122,24 +122,30 @@ public class NPMPackageGenerator {
p.addProperty("type", PackageType.SUBSET.getCode()); p.addProperty("type", PackageType.SUBSET.getCode());
p.remove("title"); p.remove("title");
p.addProperty("title", name); p.addProperty("title", name);
if (notForPublication) {
p.addProperty("notForPublication", true);
}
return new NPMPackageGenerator(destFile, p, date); return new NPMPackageGenerator(destFile, p, date, notForPublication);
} }
public NPMPackageGenerator(String destFile, String canonical, String url, PackageType kind, ImplementationGuide ig, Date date, List<String> fhirVersion) throws FHIRException, IOException { public NPMPackageGenerator(String destFile, String canonical, String url, PackageType kind, ImplementationGuide ig, Date date, List<String> fhirVersion, boolean notForPublication) throws FHIRException, IOException {
super(); super();
this.destFile = destFile; this.destFile = destFile;
start(); start();
buildPackageJson(canonical, kind, url, date, ig, fhirVersion); buildPackageJson(canonical, kind, url, date, ig, fhirVersion, notForPublication);
} }
public NPMPackageGenerator(String destFile, JsonObject npm, Date date) throws FHIRException, IOException { public NPMPackageGenerator(String destFile, JsonObject npm, Date date, boolean notForPublication) throws FHIRException, IOException {
super(); super();
String dt = new SimpleDateFormat("yyyyMMddHHmmss").format(date); String dt = new SimpleDateFormat("yyyyMMddHHmmss").format(date);
packageJ = npm; packageJ = npm;
packageManifest = new JsonObject(); packageManifest = new JsonObject();
packageManifest.addProperty("version", npm.get("version").getAsString()); packageManifest.addProperty("version", npm.get("version").getAsString());
packageManifest.addProperty("date", dt); packageManifest.addProperty("date", dt);
if (notForPublication) {
packageManifest.addProperty("notForPublication", true);
}
npm.addProperty("date", dt); npm.addProperty("date", dt);
packageManifest.addProperty("name", npm.get("name").getAsString()); packageManifest.addProperty("name", npm.get("name").getAsString());
this.destFile = destFile; this.destFile = destFile;
@ -152,19 +158,23 @@ public class NPMPackageGenerator {
} }
} }
private void buildPackageJson(String canonical, PackageType kind, String web, Date date, ImplementationGuide ig, List<String> fhirVersion) throws FHIRException, IOException { private void buildPackageJson(String canonical, PackageType kind, String web, Date date, ImplementationGuide ig, List<String> fhirVersion, boolean notForPublication) throws FHIRException, IOException {
String dtHuman = new SimpleDateFormat("EEE, MMM d, yyyy HH:mmZ", new Locale("en", "US")).format(date); String dtHuman = new SimpleDateFormat("EEE, MMM d, yyyy HH:mmZ", new Locale("en", "US")).format(date);
String dt = new SimpleDateFormat("yyyyMMddHHmmss").format(date); String dt = new SimpleDateFormat("yyyyMMddHHmmss").format(date);
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
if (!ig.hasPackageId()) if (!ig.hasPackageId()) {
b.append("packageId"); b.append("packageId");
if (!ig.hasVersion()) }
if (!ig.hasVersion()) {
b.append("version"); b.append("version");
if (!ig.hasFhirVersion()) }
if (!ig.hasFhirVersion()) {
b.append("fhirVersion"); b.append("fhirVersion");
if (!ig.hasLicense()) }
if (!ig.hasLicense()) {
b.append("license"); b.append("license");
}
for (ImplementationGuideDependsOnComponent d : ig.getDependsOn()) { for (ImplementationGuideDependsOnComponent d : ig.getDependsOn()) {
if (!d.hasVersion()) { if (!d.hasVersion()) {
b.append("dependsOn.version("+d.getUri()+")"); b.append("dependsOn.version("+d.getUri()+")");
@ -177,14 +187,20 @@ public class NPMPackageGenerator {
npm.addProperty("tools-version", ToolsVersion.TOOLS_VERSION); npm.addProperty("tools-version", ToolsVersion.TOOLS_VERSION);
npm.addProperty("type", kind.getCode()); npm.addProperty("type", kind.getCode());
npm.addProperty("date", dt); npm.addProperty("date", dt);
if (ig.hasLicense()) if (ig.hasLicense()) {
npm.addProperty("license", ig.getLicense().toCode()); npm.addProperty("license", ig.getLicense().toCode());
}
npm.addProperty("canonical", canonical); npm.addProperty("canonical", canonical);
if (notForPublication) {
npm.addProperty("notForPublication", true);
}
npm.addProperty("url", web); npm.addProperty("url", web);
if (ig.hasTitle()) if (ig.hasTitle()) {
npm.addProperty("title", ig.getTitle()); npm.addProperty("title", ig.getTitle());
if (ig.hasDescription()) }
if (ig.hasDescription()) {
npm.addProperty("description", ig.getDescription()+ " (built "+dtHuman+timezone()+")"); npm.addProperty("description", ig.getDescription()+ " (built "+dtHuman+timezone()+")");
}
JsonArray vl = new JsonArray(); JsonArray vl = new JsonArray();
npm.add("fhirVersions", vl); npm.add("fhirVersions", vl);
@ -205,8 +221,9 @@ public class NPMPackageGenerator {
dep.addProperty(d.getPackageId(), d.getVersion()); dep.addProperty(d.getPackageId(), d.getVersion());
} }
} }
if (ig.hasPublisher()) if (ig.hasPublisher()) {
npm.addProperty("author", ig.getPublisher()); npm.addProperty("author", ig.getPublisher());
}
JsonArray m = new JsonArray(); JsonArray m = new JsonArray();
for (ContactDetail t : ig.getContact()) { for (ContactDetail t : ig.getContact()) {
String email = email(t.getTelecom()); String email = email(t.getTelecom());

View File

@ -11,22 +11,32 @@ import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.SystemUtils; import org.apache.commons.lang3.SystemUtils;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError; import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.context.IWorkerContext;
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.formats.IParser.OutputStyle;
import org.hl7.fhir.r5.formats.JsonParser; import org.hl7.fhir.r5.formats.JsonParser;
import org.hl7.fhir.r5.formats.XmlParser; import org.hl7.fhir.r5.formats.XmlParser;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.DomainResource; import org.hl7.fhir.r5.model.DomainResource;
import org.hl7.fhir.r5.model.Questionnaire; import org.hl7.fhir.r5.model.Questionnaire;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.renderers.RendererFactory; import org.hl7.fhir.r5.renderers.RendererFactory;
import org.hl7.fhir.r5.renderers.ResourceRenderer; import org.hl7.fhir.r5.renderers.ResourceRenderer;
import org.hl7.fhir.r5.renderers.utils.ElementWrappers;
import org.hl7.fhir.r5.renderers.utils.RenderingContext; import org.hl7.fhir.r5.renderers.utils.RenderingContext;
import org.hl7.fhir.r5.renderers.utils.RenderingContext.ITypeParser;
import org.hl7.fhir.r5.renderers.utils.RenderingContext.QuestionnaireRendererMode; import org.hl7.fhir.r5.renderers.utils.RenderingContext.QuestionnaireRendererMode;
import org.hl7.fhir.r5.renderers.utils.RenderingContext.ResourceRendererMode; import org.hl7.fhir.r5.renderers.utils.RenderingContext.ResourceRendererMode;
import org.hl7.fhir.r5.test.NarrativeGenerationTests.TestTypeParser;
import org.hl7.fhir.r5.test.utils.TestingUtilities; import org.hl7.fhir.r5.test.utils.TestingUtilities;
import org.hl7.fhir.utilities.TerminologyServiceOptions; import org.hl7.fhir.utilities.TerminologyServiceOptions;
import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.xhtml.XhtmlComposer; import org.hl7.fhir.utilities.xhtml.XhtmlComposer;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
import org.hl7.fhir.utilities.xhtml.XhtmlParser;
import org.hl7.fhir.utilities.xml.XMLUtil; import org.hl7.fhir.utilities.xml.XMLUtil;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
@ -40,6 +50,15 @@ import org.xml.sax.SAXException;
public class NarrativeGenerationTests { public class NarrativeGenerationTests {
public class TestTypeParser implements ITypeParser {
@Override
public Base parseType(String xml, String type) throws FHIRFormatError, IOException, FHIRException {
return new org.hl7.fhir.r5.formats.XmlParser().parseType(xml, type);
}
}
public static final String WINDOWS = "WINDOWS"; public static final String WINDOWS = "WINDOWS";
private static final String HEADER = "<html><head>"+ private static final String HEADER = "<html><head>"+
@ -57,11 +76,13 @@ public class NarrativeGenerationTests {
public static class TestDetails { public static class TestDetails {
private String id; private String id;
private boolean header; private boolean header;
private boolean meta;
public TestDetails(Element test) { public TestDetails(Element test) {
super(); super();
id = test.getAttribute("id"); id = test.getAttribute("id");
header = "true".equals(test.getAttribute("header")); header = "true".equals(test.getAttribute("header"));
meta = "true".equals(test.getAttribute("meta"));
} }
public String getId() { public String getId() {
@ -70,6 +91,10 @@ public class NarrativeGenerationTests {
public boolean isHeader() { public boolean isHeader() {
return header; return header;
}
public boolean isMeta() {
return meta;
} }
} }
@ -107,19 +132,30 @@ public class NarrativeGenerationTests {
rc.setHeader(test.isHeader()); rc.setHeader(test.isHeader());
rc.setDefinitionsTarget("test.html"); rc.setDefinitionsTarget("test.html");
rc.setTerminologyServiceOptions(TerminologyServiceOptions.defaults()); rc.setTerminologyServiceOptions(TerminologyServiceOptions.defaults());
IOUtils.copy(TestingUtilities.loadTestResourceStream("r5", "narrative", test.getId() + "-expected.xml"), new FileOutputStream(TestingUtilities.tempFile("narrative", test.getId() + "-expected.xml"))); rc.setParser(new TestTypeParser());
DomainResource source; Resource source;
if (TestingUtilities.findTestResource("r5", "narrative", test.getId() + "-input.json")) { if (TestingUtilities.findTestResource("r5", "narrative", test.getId() + ".json")) {
source = (DomainResource) new JsonParser().parse(TestingUtilities.loadTestResourceStream("r5", "narrative", test.getId() + "-input.json")); source = (Resource) new JsonParser().parse(TestingUtilities.loadTestResourceStream("r5", "narrative", test.getId() + ".json"));
} else { } else {
source = (DomainResource) new XmlParser().parse(TestingUtilities.loadTestResourceStream("r5", "narrative", test.getId() + "-input.xml")); source = (Resource) new XmlParser().parse(TestingUtilities.loadTestResourceStream("r5", "narrative", test.getId() + ".xml"));
}
XhtmlNode x = RendererFactory.factory(source, rc).build(source);
String target = TextFile.streamToString(TestingUtilities.loadTestResourceStream("r5", "narrative", test.getId() + ".html"));
String output = HEADER+new XhtmlComposer(true, true).compose(x)+FOOTER;
TextFile.stringToFile(target, TestingUtilities.tempFile("narrative", test.getId() + ".target.html"));
TextFile.stringToFile(output, TestingUtilities.tempFile("narrative", test.getId() + ".output.html"));
Assertions.assertTrue(output.equals(target), "Output does not match expected");
if (test.isMeta()) {
org.hl7.fhir.r5.elementmodel.Element e = Manager.parse(context, TestingUtilities.loadTestResourceStream("r5", "narrative", test.getId() + ".xml"), FhirFormat.XML);
x = RendererFactory.factory(source, rc).render(new ElementWrappers.ResourceWrapperMetaElement(rc, e));
target = TextFile.streamToString(TestingUtilities.loadTestResourceStream("r5", "narrative", test.getId() + "-meta.html"));
output = HEADER+new XhtmlComposer(true).compose(x)+FOOTER;
TextFile.stringToFile(output, TestingUtilities.tempFile("narrative", test.getId() + "-meta.output.html"));
Assertions.assertTrue(output.equals(target), "Output does not match expected (meta)");
} }
DomainResource target = (DomainResource) new XmlParser().parse(TestingUtilities.loadTestResourceStream("r5", "narrative", test.getId() + "-expected.xml"));
RendererFactory.factory(source, rc).render(source);
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(TestingUtilities.tempFile("narrative", test.getId() + "-actual.xml")), source);
source = (DomainResource) new XmlParser().parse(new FileInputStream(TestingUtilities.tempFile("narrative", test.getId() + "-actual.xml")));
String html = HEADER+new XhtmlComposer(true).compose(source.getText().getDiv())+FOOTER;
TextFile.stringToFile(html, TestingUtilities.tempFile("narrative", test.getId() + ".html"));
Assertions.assertTrue(source.equalsDeep(target), "Output does not match expected");
} }
} }

View File

@ -13,6 +13,7 @@ import org.hl7.fhir.r5.formats.IParser.OutputStyle;
import org.hl7.fhir.r5.formats.JsonParser; import org.hl7.fhir.r5.formats.JsonParser;
import org.hl7.fhir.r5.formats.XmlParser; import org.hl7.fhir.r5.formats.XmlParser;
import org.hl7.fhir.r5.model.Bundle; import org.hl7.fhir.r5.model.Bundle;
import org.hl7.fhir.r5.model.DateTimeType;
import org.hl7.fhir.r5.model.DomainResource; import org.hl7.fhir.r5.model.DomainResource;
import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.renderers.RendererFactory; import org.hl7.fhir.r5.renderers.RendererFactory;
@ -20,6 +21,7 @@ import org.hl7.fhir.r5.renderers.utils.RenderingContext;
import org.hl7.fhir.r5.renderers.utils.RenderingContext.ResourceRendererMode; import org.hl7.fhir.r5.renderers.utils.RenderingContext.ResourceRendererMode;
import org.hl7.fhir.r5.test.utils.TestingUtilities; import org.hl7.fhir.r5.test.utils.TestingUtilities;
import org.hl7.fhir.r5.utils.EOperationOutcome; import org.hl7.fhir.r5.utils.EOperationOutcome;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
public class ResourceRoundTripTests { public class ResourceRoundTripTests {
@ -52,4 +54,5 @@ public class ResourceRoundTripTests {
if (result == null) if (result == null)
throw new FHIRException("Bundle was null"); throw new FHIRException("Bundle was null");
} }
} }

View File

@ -1091,6 +1091,10 @@ public class NpmPackage {
} }
return true; return true;
} }
public boolean isNotForPublication() {
return JSONUtil.bool(npm, "notForPublication");
}
} }

View File

@ -741,6 +741,12 @@ public class XhtmlNode implements IBaseXhtml {
} }
public XhtmlNode backgroundColor(String color) {
style("background-color: "+color);
return this;
}

View File

@ -17,7 +17,7 @@
<properties> <properties>
<hapi_fhir_version>5.1.0</hapi_fhir_version> <hapi_fhir_version>5.1.0</hapi_fhir_version>
<validator_test_case_version>1.1.35</validator_test_case_version> <validator_test_case_version>1.1.36-SNAPSHOT</validator_test_case_version>
<junit_jupiter_version>5.6.2</junit_jupiter_version> <junit_jupiter_version>5.6.2</junit_jupiter_version>
<maven_surefire_version>3.0.0-M4</maven_surefire_version> <maven_surefire_version>3.0.0-M4</maven_surefire_version>
<jacoco_version>0.8.5</jacoco_version> <jacoco_version>0.8.5</jacoco_version>