Reconcile R4/R5 implementations
This commit is contained in:
parent
07f4743cd1
commit
512c3932a3
|
@ -891,7 +891,7 @@ public class ProfileComparer {
|
|||
if (nw.hasAggregation())
|
||||
throw new DefinitionException("Aggregation not supported: "+path);
|
||||
for (TypeRefComponent ex : results) {
|
||||
if (Utilities.equals(ex.getCode(), nw.getCode())) {
|
||||
if (Utilities.equals(ex.getWorkingCode(), nw.getWorkingCode())) {
|
||||
if (!ex.hasProfile() && !nw.hasProfile())
|
||||
pfound = true;
|
||||
else if (!ex.hasProfile()) {
|
||||
|
@ -1070,7 +1070,7 @@ public class ProfileComparer {
|
|||
private String typeCode(DefinitionNavigator defn) {
|
||||
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
|
||||
for (TypeRefComponent t : defn.current().getType())
|
||||
b.append(t.getCode()+(t.hasProfile() ? "("+t.getProfile()+")" : "")+(t.hasTargetProfile() ? "("+t.getTargetProfile()+")" : "")); // todo: other properties
|
||||
b.append(t.getWorkingCode()+(t.hasProfile() ? "("+t.getProfile()+")" : "")+(t.hasTargetProfile() ? "("+t.getTargetProfile()+")" : "")); // todo: other properties
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
|
|
|
@ -264,14 +264,15 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
public String display;
|
||||
public String url;
|
||||
}
|
||||
boolean isDatatype(String typeSimple);
|
||||
boolean isResource(String typeSimple);
|
||||
boolean hasLinkFor(String typeSimple);
|
||||
String getLinkFor(String corePath, String typeSimple);
|
||||
BindingResolution resolveBinding(StructureDefinition def, ElementDefinitionBindingComponent binding, String path) throws FHIRException;
|
||||
BindingResolution resolveBinding(StructureDefinition def, String url, String path) throws FHIRException;
|
||||
String getLinkForProfile(StructureDefinition profile, String url);
|
||||
boolean prependLinks();
|
||||
public boolean isDatatype(String typeSimple);
|
||||
public boolean isResource(String typeSimple);
|
||||
public boolean hasLinkFor(String typeSimple);
|
||||
public String getLinkFor(String corePath, String typeSimple);
|
||||
public BindingResolution resolveBinding(StructureDefinition def, ElementDefinitionBindingComponent binding, String path) throws FHIRException;
|
||||
public BindingResolution resolveBinding(StructureDefinition def, String url, String path) throws FHIRException;
|
||||
public String getLinkForProfile(StructureDefinition profile, String url);
|
||||
public boolean prependLinks();
|
||||
public String getLinkForUrl(String corePath, String s);
|
||||
}
|
||||
|
||||
|
||||
|
@ -448,7 +449,7 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
e.clearUserData(GENERATED_IN_SNAPSHOT);
|
||||
|
||||
// we actually delegate the work to a subroutine so we can re-enter it with a different cursors
|
||||
StructureDefinitionDifferentialComponent diff = derived.getDifferential().copy(); // we make a copy here because we're sometimes going to hack the differential while processing it.
|
||||
StructureDefinitionDifferentialComponent diff = cloneDiff(derived.getDifferential()); // we make a copy here because we're sometimes going to hack the differential while processing it. Have to migrate user data back afterwards
|
||||
|
||||
processPaths("", derived.getSnapshot(), base.getSnapshot(), diff, baseCursor, diffCursor, base.getSnapshot().getElement().size()-1,
|
||||
derived.getDifferential().hasElement() ? derived.getDifferential().getElement().size()-1 : -1, url, webUrl, derived.present(), null, null, false, base.getUrl(), null, false, new ArrayList<ElementRedirection>(), base);
|
||||
|
@ -467,6 +468,14 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
setIds(derived, false);
|
||||
//Check that all differential elements have a corresponding snapshot element
|
||||
for (ElementDefinition e : diff.getElement()) {
|
||||
if (!e.hasUserData("diff-source"))
|
||||
throw new Error("Unxpected internal condition - no source on diff element");
|
||||
else {
|
||||
if (e.hasUserData(DERIVATION_EQUALS))
|
||||
((Base) e.getUserData("diff-source")).setUserData(DERIVATION_EQUALS, e.getUserData(DERIVATION_EQUALS));
|
||||
if (e.hasUserData(DERIVATION_POINTER))
|
||||
((Base) e.getUserData("diff-source")).setUserData(DERIVATION_POINTER, e.getUserData(DERIVATION_POINTER));
|
||||
}
|
||||
if (!e.hasUserData(GENERATED_IN_SNAPSHOT)) {
|
||||
System.out.println("Error in snapshot generation: Differential for "+derived.getUrl()+" with " + (e.hasId() ? "id: "+e.getId() : "path: "+e.getPath())+" has an element that is not marked with a snapshot match");
|
||||
if (exception)
|
||||
|
@ -489,6 +498,17 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
}
|
||||
}
|
||||
|
||||
private StructureDefinitionDifferentialComponent cloneDiff(StructureDefinitionDifferentialComponent source) {
|
||||
StructureDefinitionDifferentialComponent diff = new StructureDefinitionDifferentialComponent();
|
||||
for (ElementDefinition sed : source.getElement()) {
|
||||
ElementDefinition ted = sed.copy();
|
||||
diff.getElement().add(ted);
|
||||
ted.setUserData("diff-source", sed);
|
||||
}
|
||||
return diff;
|
||||
}
|
||||
|
||||
|
||||
private String constraintSummary(ElementDefinition ed) {
|
||||
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
|
||||
if (ed.hasPattern())
|
||||
|
@ -528,7 +548,7 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
first = false;
|
||||
else
|
||||
b.append("|");
|
||||
b.append(tr.getCode());
|
||||
b.append(tr.getWorkingCode());
|
||||
}
|
||||
return b.toString();
|
||||
}
|
||||
|
@ -541,7 +561,7 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
first = false;
|
||||
else
|
||||
b.append("|");
|
||||
b.append(tr.getCode());
|
||||
b.append(tr.getWorkingCode());
|
||||
if (tr.hasProfile()) {
|
||||
b.append("(");
|
||||
b.append(tr.getProfile());
|
||||
|
@ -613,7 +633,7 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
}
|
||||
if (outcome.getType().size() > 1) {
|
||||
for (TypeRefComponent t : outcome.getType()) {
|
||||
if (!t.getCode().equals("Reference"))
|
||||
if (!t.getWorkingCode().equals("Reference"))
|
||||
throw new DefinitionException(diffMatches.get(0).getPath()+" has children ("+differential.getElement().get(diffCursor).getPath()+") and multiple types ("+typeCode(outcome.getType())+") in profile "+profileName);
|
||||
}
|
||||
}
|
||||
|
@ -631,7 +651,7 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
baseCursor++;
|
||||
} else if (diffMatches.size() == 1 && (slicingDone || (!isImplicitSlicing(diffMatches.get(0), cpath) && !(diffMatches.get(0).hasSlicing() || (isExtension(diffMatches.get(0)) && diffMatches.get(0).hasSliceName()))))) {// one matching element in the differential
|
||||
ElementDefinition template = null;
|
||||
if (diffMatches.get(0).hasType() && diffMatches.get(0).getType().size() == 1 && diffMatches.get(0).getType().get(0).hasProfile() && !"Reference".equals(diffMatches.get(0).getType().get(0).getCode())) {
|
||||
if (diffMatches.get(0).hasType() && diffMatches.get(0).getType().size() == 1 && diffMatches.get(0).getType().get(0).hasProfile() && !"Reference".equals(diffMatches.get(0).getType().get(0).getWorkingCode())) {
|
||||
CanonicalType p = diffMatches.get(0).getType().get(0).getProfile().get(0);
|
||||
StructureDefinition sd = context.fetchResource(StructureDefinition.class, p.getValue());
|
||||
if (sd != null) {
|
||||
|
@ -1182,10 +1202,12 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
String s = n.substring(rn.length());
|
||||
if (!s.contains(".")) {
|
||||
if (ed.hasSliceName() && ed.getType().size() == 1) {
|
||||
typeList.add(new TypeSlice(ed, ed.getTypeFirstRep().getCode()));
|
||||
typeList.add(new TypeSlice(ed, ed.getTypeFirstRep().getWorkingCode()));
|
||||
} else if (!ed.hasSliceName() && !s.equals("[x]")) {
|
||||
if (isDataType(s))
|
||||
typeList.add(new TypeSlice(ed, s));
|
||||
else if (isConstrainedDataType(s))
|
||||
typeList.add(new TypeSlice(ed, baseType(s)));
|
||||
else if (isPrimitive(Utilities.uncapitalize(s)))
|
||||
typeList.add(new TypeSlice(ed, Utilities.uncapitalize(s)));
|
||||
} else if (!ed.hasSliceName() && s.equals("[x]"))
|
||||
|
@ -1207,7 +1229,7 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
private List<TypeRefComponent> getByTypeName(List<TypeRefComponent> type, String t) {
|
||||
List<TypeRefComponent> res = new ArrayList<TypeRefComponent>();
|
||||
for (TypeRefComponent tr : type) {
|
||||
if (t.equals(tr.getCode()))
|
||||
if (t.equals(tr.getWorkingCode()))
|
||||
res.add(tr);
|
||||
}
|
||||
return res;
|
||||
|
@ -1401,9 +1423,9 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
System.out.println("Failed to find referenced profile: " + type.getProfile());
|
||||
}
|
||||
if (sd == null)
|
||||
sd = context.fetchTypeDefinition(type.getCode());
|
||||
sd = context.fetchTypeDefinition(type.getWorkingCode());
|
||||
if (sd == null)
|
||||
System.out.println("XX: failed to find profle for type: " + type.getCode()); // debug GJM
|
||||
System.out.println("XX: failed to find profle for type: " + type.getWorkingCode()); // debug GJM
|
||||
return sd;
|
||||
}
|
||||
|
||||
|
@ -1420,7 +1442,7 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
boolean first = true;
|
||||
for (TypeRefComponent type : types) {
|
||||
if (first) first = false; else b.append(", ");
|
||||
b.append(type.getCode());
|
||||
b.append(type.getWorkingCode());
|
||||
if (type.hasTargetProfile())
|
||||
b.append("{"+type.getTargetProfile()+"}");
|
||||
else if (type.hasProfile())
|
||||
|
@ -1434,7 +1456,7 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
if (types.isEmpty())
|
||||
return false;
|
||||
for (TypeRefComponent type : types) {
|
||||
String t = type.getCode();
|
||||
String t = type.getWorkingCode();
|
||||
if (!isDataType(t) && !isPrimitive(t))
|
||||
return false;
|
||||
}
|
||||
|
@ -1894,15 +1916,11 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
// }
|
||||
boolean ok = false;
|
||||
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
|
||||
String t = ts.getCode();
|
||||
if (t == null && ts.getCodeElement().hasExtension(ToolingExtensions.EXT_XML_TYPE))
|
||||
t = "*"; //
|
||||
String t = ts.getWorkingCode();
|
||||
for (TypeRefComponent td : base.getType()) {;
|
||||
String tt = td.getCode();
|
||||
if (tt == null && td.getCodeElement().hasExtension(ToolingExtensions.EXT_JSON_TYPE))
|
||||
tt = "*"; //
|
||||
String tt = td.getWorkingCode();
|
||||
b.append(tt);
|
||||
if (td.hasCode() && (tt.equals(t) || "Extension".equals(tt) ||
|
||||
if (td.hasCode() && (tt.equals(t) || "Extension".equals(tt) || (t.equals("uri") && tt.equals("string")) || // work around for old badly generated SDs
|
||||
"Element".equals(tt) || "*".equals(tt) ||
|
||||
(("Resource".equals(tt) || ("DomainResource".equals(tt)) && pkp.isResource(t)))))
|
||||
ok = true;
|
||||
|
@ -1973,7 +1991,7 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
|
||||
private boolean hasBindableType(ElementDefinition ed) {
|
||||
for (TypeRefComponent tr : ed.getType()) {
|
||||
if (Utilities.existsInList(tr.getCode(), "Coding", "CodeableConcept", "Quantity", "uri", "string", "code"))
|
||||
if (Utilities.existsInList(tr.getWorkingCode(), "Coding", "CodeableConcept", "Quantity", "uri", "string", "code"))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -2255,7 +2273,7 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
c.addPiece(checkForNoChange(tl, gen.new Piece(null,", ", null)));
|
||||
tl = t;
|
||||
if (t.hasTarget()) {
|
||||
c.getPieces().add(gen.new Piece(corePath+"references.html", t.getCode(), null));
|
||||
c.getPieces().add(gen.new Piece(corePath+"references.html", t.getWorkingCode(), null));
|
||||
c.getPieces().add(gen.new Piece(null, "(", null));
|
||||
boolean tfirst = true;
|
||||
for (UriType u : t.getTargetProfile()) {
|
||||
|
@ -2263,27 +2281,7 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
tfirst = false;
|
||||
else
|
||||
c.addPiece(gen.new Piece(null, " | ", null));
|
||||
if (u.getValue().startsWith("http://hl7.org/fhir/StructureDefinition/")) {
|
||||
StructureDefinition sd = context.fetchResource(StructureDefinition.class, u.getValue());
|
||||
if (sd != null) {
|
||||
String disp = sd.hasTitle() ? sd.getTitle() : sd.getName();
|
||||
c.addPiece(checkForNoChange(t, gen.new Piece(checkPrepend(corePath, sd.getUserString("path")), disp, null)));
|
||||
} else {
|
||||
String rn = u.getValue().substring(40);
|
||||
c.addPiece(checkForNoChange(t, gen.new Piece(pkp.getLinkFor(corePath, rn), rn, null)));
|
||||
}
|
||||
} else if (Utilities.isAbsoluteUrl(u.getValue())) {
|
||||
StructureDefinition sd = context.fetchResource(StructureDefinition.class, u.getValue());
|
||||
if (sd != null) {
|
||||
String disp = sd.hasTitle() ? sd.getTitle() : sd.getName();
|
||||
String ref = pkp.getLinkForProfile(null, sd.getUrl());
|
||||
if (ref.contains("|"))
|
||||
ref = ref.substring(0, ref.indexOf("|"));
|
||||
c.addPiece(checkForNoChange(t, gen.new Piece(ref, disp, null)));
|
||||
} else
|
||||
c.addPiece(checkForNoChange(t, gen.new Piece(null, u.getValue(), null)));
|
||||
} else if (t.hasTargetProfile() && u.getValue().startsWith("#"))
|
||||
c.addPiece(checkForNoChange(t, gen.new Piece(corePath+profileBaseFileName+"."+u.getValue().substring(1).toLowerCase()+".html", u.getValue(), null)));
|
||||
genTargetLink(gen, profileBaseFileName, corePath, c, t, u.getValue());
|
||||
}
|
||||
c.getPieces().add(gen.new Piece(null, ")", null));
|
||||
if (t.getAggregation().size() > 0) {
|
||||
|
@ -2298,24 +2296,22 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
}
|
||||
c.getPieces().add(gen.new Piece(corePath+"valueset-resource-aggregation-mode.html", "}", null));
|
||||
}
|
||||
} else if (t.hasProfile() && (!t.getCode().equals("Extension") || isProfiledType(t.getProfile()))) { // a profiled type
|
||||
} else if (t.hasProfile() && (!t.getWorkingCode().equals("Extension") || isProfiledType(t.getProfile()))) { // a profiled type
|
||||
String ref;
|
||||
ref = pkp.getLinkForProfile(profile, t.getProfile().get(0).getValue());
|
||||
if (ref != null) {
|
||||
String[] parts = ref.split("\\|");
|
||||
if (parts[0].startsWith("http:") || parts[0].startsWith("https:")) {
|
||||
// c.addPiece(checkForNoChange(t, gen.new Piece(parts[0], "<" + parts[1] + ">", t.getCode()))); Lloyd
|
||||
c.addPiece(checkForNoChange(t, gen.new Piece(parts[0], parts[1], t.getCode())));
|
||||
c.addPiece(checkForNoChange(t, gen.new Piece(parts[0], parts[1], t.getWorkingCode())));
|
||||
} else {
|
||||
// c.addPiece(checkForNoChange(t, gen.new Piece((t.getProfile().startsWith(corePath)? corePath: "")+parts[0], "<" + parts[1] + ">", t.getCode())));
|
||||
c.addPiece(checkForNoChange(t, gen.new Piece((t.getProfile().get(0).getValue().startsWith(corePath+"StructureDefinition")? corePath: "")+parts[0], parts[1], t.getCode())));
|
||||
c.addPiece(checkForNoChange(t, gen.new Piece((t.getProfile().get(0).getValue().startsWith(corePath+"StructureDefinition")? corePath: "")+parts[0], parts[1], t.getWorkingCode())));
|
||||
}
|
||||
} else
|
||||
c.addPiece(checkForNoChange(t, gen.new Piece((t.getProfile().get(0).getValue().startsWith(corePath)? corePath: "")+ref, t.getCode(), null)));
|
||||
c.addPiece(checkForNoChange(t, gen.new Piece((t.getProfile().get(0).getValue().startsWith(corePath)? corePath: "")+ref, t.getWorkingCode(), null)));
|
||||
} else {
|
||||
String tc = t.getCode();
|
||||
if (Utilities.noString(tc) && t.getCodeElement().hasExtension(ToolingExtensions.EXT_JSON_TYPE))
|
||||
tc = "string";
|
||||
String tc = t.getWorkingCode();
|
||||
if (pkp != null && pkp.hasLinkFor(tc)) {
|
||||
c.addPiece(checkForNoChange(t, gen.new Piece(pkp.getLinkFor(corePath, tc), tc, null)));
|
||||
} else
|
||||
|
@ -2325,6 +2321,31 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
return c;
|
||||
}
|
||||
|
||||
|
||||
public void genTargetLink(HierarchicalTableGenerator gen, String profileBaseFileName, String corePath, Cell c, TypeRefComponent t, String u) {
|
||||
if (u.startsWith("http://hl7.org/fhir/StructureDefinition/")) {
|
||||
StructureDefinition sd = context.fetchResource(StructureDefinition.class, u);
|
||||
if (sd != null) {
|
||||
String disp = sd.hasTitle() ? sd.getTitle() : sd.getName();
|
||||
c.addPiece(checkForNoChange(t, gen.new Piece(checkPrepend(corePath, sd.getUserString("path")), disp, null)));
|
||||
} else {
|
||||
String rn = u.substring(40);
|
||||
c.addPiece(checkForNoChange(t, gen.new Piece(pkp.getLinkFor(corePath, rn), rn, null)));
|
||||
}
|
||||
} else if (Utilities.isAbsoluteUrl(u)) {
|
||||
StructureDefinition sd = context.fetchResource(StructureDefinition.class, u);
|
||||
if (sd != null) {
|
||||
String disp = sd.hasTitle() ? sd.getTitle() : sd.getName();
|
||||
String ref = pkp.getLinkForProfile(null, sd.getUrl());
|
||||
if (ref.contains("|"))
|
||||
ref = ref.substring(0, ref.indexOf("|"));
|
||||
c.addPiece(checkForNoChange(t, gen.new Piece(ref, disp, null)));
|
||||
} else
|
||||
c.addPiece(checkForNoChange(t, gen.new Piece(null, u, null)));
|
||||
} else if (t.hasTargetProfile() && u.startsWith("#"))
|
||||
c.addPiece(checkForNoChange(t, gen.new Piece(corePath+profileBaseFileName+"."+u.substring(1).toLowerCase()+".html", u, null)));
|
||||
}
|
||||
|
||||
private boolean isProfiledType(List<CanonicalType> theProfile) {
|
||||
for (CanonicalType next : theProfile){
|
||||
if (StringUtils.defaultString(next.getValueAsString()).contains(":")) {
|
||||
|
@ -2473,8 +2494,11 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
List<ElementDefinition> list = diff ? profile.getDifferential().getElement() : profile.getSnapshot().getElement();
|
||||
List<StructureDefinition> profiles = new ArrayList<StructureDefinition>();
|
||||
profiles.add(profile);
|
||||
if (list.isEmpty())
|
||||
throw new FHIRException((diff ? "Differential" : "Snapshot") + " is empty generating hierarchical table for "+profile.getUrl());
|
||||
if (list.isEmpty()) {
|
||||
ElementDefinition root = new ElementDefinition().setPath(profile.getType());
|
||||
root.setId(profile.getType());
|
||||
list.add(root);
|
||||
}
|
||||
genElement(defFile == null ? null : defFile+"#", gen, model.getRows(), list.get(0), list, profiles, diff, profileBaseFileName, null, snapshot, corePath, imagePath, true, logicalModel, profile.getDerivation() == TypeDerivationRule.CONSTRAINT && usesMustSupport(list), allInvariants, null);
|
||||
try {
|
||||
return gen.generate(model, imagePath, 0, outputTracker);
|
||||
|
@ -2513,7 +2537,7 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
StructureDefinition profile = profiles == null ? null : profiles.get(profiles.size()-1);
|
||||
String s = tail(element.getPath());
|
||||
if (element.hasSliceName())
|
||||
s = element.getSliceName();
|
||||
s = s +":"+element.getSliceName();
|
||||
Row typesRow = null;
|
||||
|
||||
List<ElementDefinition> children = getChildren(all, element);
|
||||
|
@ -2533,13 +2557,13 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
row.setLineColor(0);
|
||||
boolean hasDef = element != null;
|
||||
boolean ext = false;
|
||||
if (s.equals("extension")) {
|
||||
if (tail(element.getPath()).equals("extension")) {
|
||||
if (element.hasType() && element.getType().get(0).hasProfile() && extensionIsComplex(element.getType().get(0).getProfile().get(0).getValue()))
|
||||
row.setIcon("icon_extension_complex.png", HierarchicalTableGenerator.TEXT_ICON_EXTENSION_COMPLEX);
|
||||
else
|
||||
row.setIcon("icon_extension_simple.png", HierarchicalTableGenerator.TEXT_ICON_EXTENSION_SIMPLE);
|
||||
ext = true;
|
||||
} else if (s.equals("modifierExtension")) {
|
||||
} else if (tail(element.getPath()).equals("modifierExtension")) {
|
||||
if (element.hasType() && element.getType().get(0).hasProfile() && extensionIsComplex(element.getType().get(0).getProfile().get(0).getValue()))
|
||||
row.setIcon("icon_modifier_extension_complex.png", HierarchicalTableGenerator.TEXT_ICON_EXTENSION_COMPLEX);
|
||||
else
|
||||
|
@ -2553,13 +2577,13 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
row.setIcon("icon_choice.gif", HierarchicalTableGenerator.TEXT_ICON_CHOICE);
|
||||
typesRow = row;
|
||||
}
|
||||
} else if (hasDef && element.getType().get(0).getCode() != null && element.getType().get(0).getCode().startsWith("@"))
|
||||
} else if (hasDef && element.getType().get(0).getWorkingCode() != null && element.getType().get(0).getWorkingCode().startsWith("@"))
|
||||
row.setIcon("icon_reuse.png", HierarchicalTableGenerator.TEXT_ICON_REUSE);
|
||||
else if (hasDef && isPrimitive(element.getType().get(0).getCode()))
|
||||
else if (hasDef && isPrimitive(element.getType().get(0).getWorkingCode()))
|
||||
row.setIcon("icon_primitive.png", HierarchicalTableGenerator.TEXT_ICON_PRIMITIVE);
|
||||
else if (hasDef && element.getType().get(0).hasTarget())
|
||||
row.setIcon("icon_reference.png", HierarchicalTableGenerator.TEXT_ICON_REFERENCE);
|
||||
else if (hasDef && isDataType(element.getType().get(0).getCode()))
|
||||
else if (hasDef && isDataType(element.getType().get(0).getWorkingCode()))
|
||||
row.setIcon("icon_datatype.gif", HierarchicalTableGenerator.TEXT_ICON_DATATYPE);
|
||||
else
|
||||
row.setIcon("icon_resource.png", HierarchicalTableGenerator.TEXT_ICON_RESOURCE);
|
||||
|
@ -2629,12 +2653,13 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
} else {
|
||||
row.setIcon("icon_slice.png", HierarchicalTableGenerator.TEXT_ICON_SLICE);
|
||||
slicingRow = row;
|
||||
row.getCells().get(2).getPieces().clear();
|
||||
for (Cell cell : row.getCells())
|
||||
for (Piece p : cell.getPieces()) {
|
||||
p.addStyle("font-style: italic");
|
||||
}
|
||||
}
|
||||
} else if (element.hasSliceName()) {
|
||||
row.setIcon("icon_slice_item.png", HierarchicalTableGenerator.TEXT_ICON_SLICE_ITEM);
|
||||
}
|
||||
if (used.used || showMissing)
|
||||
rows.add(row);
|
||||
|
@ -2689,17 +2714,17 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
// genElement(defPath, gen, row.getSubRows(), child, all, profiles, showMissing, profileBaseFileName, true, false, corePath, imagePath, false, logicalModel, isConstraintMode, allInvariants);
|
||||
}
|
||||
if (typesRow != null) {
|
||||
makeChoiceRows(typesRow.getSubRows(), element, gen, corePath);
|
||||
makeChoiceRows(typesRow.getSubRows(), element, gen, corePath, profileBaseFileName);
|
||||
}
|
||||
}
|
||||
return slicingRow;
|
||||
}
|
||||
|
||||
private void makeChoiceRows(List<Row> subRows, ElementDefinition element, HierarchicalTableGenerator gen, String corePath) {
|
||||
private void makeChoiceRows(List<Row> subRows, ElementDefinition element, HierarchicalTableGenerator gen, String corePath, String profileBaseFileName) {
|
||||
// create a child for each choice
|
||||
for (TypeRefComponent tr : element.getType()) {
|
||||
Row choicerow = gen.new Row();
|
||||
String t = tr.getCode();
|
||||
String t = tr.getWorkingCode();
|
||||
if (isReference(t)) {
|
||||
choicerow.getCells().add(gen.new Cell(null, null, tail(element.getPath()).replace("[x]", Utilities.capitalize(t)), null, null));
|
||||
choicerow.getCells().add(gen.new Cell());
|
||||
|
@ -2708,7 +2733,7 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
Cell c = gen.new Cell();
|
||||
choicerow.getCells().add(c);
|
||||
if (ADD_REFERENCE_TO_TABLE) {
|
||||
if (tr.getCode().equals("canonical"))
|
||||
if (tr.getWorkingCode().equals("canonical"))
|
||||
c.getPieces().add(gen.new Piece(corePath+"datatypes.html#canonical", "canonical", null));
|
||||
else
|
||||
c.getPieces().add(gen.new Piece(corePath+"references.html#Reference", "Reference", null));
|
||||
|
@ -2718,7 +2743,7 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
for (CanonicalType rt : tr.getTargetProfile()) {
|
||||
if (!first)
|
||||
c.getPieces().add(gen.new Piece(null, " | ", null));
|
||||
c.getPieces().add(gen.new Piece(null, pkp.getLinkFor(corePath, rt.asStringValue()), null));
|
||||
genTargetLink(gen, profileBaseFileName, corePath, c, tr, rt.getValue());
|
||||
first = false;
|
||||
}
|
||||
if (ADD_REFERENCE_TO_TABLE)
|
||||
|
@ -3034,9 +3059,13 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
if (definition.hasFixed()) {
|
||||
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")));
|
||||
if (!useTableForFixedValues || definition.getFixed().isPrimitive())
|
||||
c.getPieces().add(checkForNoChange(definition.getFixed(), gen.new Piece(null, buildJson(definition.getFixed()), null).addStyle("color: darkgreen")));
|
||||
else {
|
||||
if (!useTableForFixedValues || definition.getFixed().isPrimitive()) {
|
||||
String s = buildJson(definition.getFixed());
|
||||
String link = null;
|
||||
if (Utilities.isAbsoluteUrl(s))
|
||||
link = pkp.getLinkForUrl(corePath, s);
|
||||
c.getPieces().add(checkForNoChange(definition.getFixed(), gen.new Piece(link, s, null).addStyle("color: darkgreen")));
|
||||
} else {
|
||||
c.getPieces().add(checkForNoChange(definition.getFixed(), gen.new Piece(null, "As shown", null).addStyle("color: darkgreen")));
|
||||
genFixedValue(gen, row, definition.getFixed(), snapshot, false, corePath);
|
||||
}
|
||||
|
@ -3158,9 +3187,11 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
c.addPiece(gen.new Piece("br"));
|
||||
c.getPieces().add(gen.new Piece(null, "Fixed Value: ", null).addStyle("font-weight: bold"));
|
||||
String s = b.primitiveValue();
|
||||
if (Utilities.noString(s))
|
||||
System.out.print("t");
|
||||
c.getPieces().add(gen.new Piece(null, s, null).addStyle("color: darkgreen"));
|
||||
// ok. let's see if we can find a relevant link for this
|
||||
String link = null;
|
||||
if (Utilities.isAbsoluteUrl(s))
|
||||
link = pkp.getLinkForUrl(corePath, s);
|
||||
c.getPieces().add(gen.new Piece(link, s, null).addStyle("color: darkgreen"));
|
||||
} else {
|
||||
c = gen.new Cell();
|
||||
row.getCells().add(c);
|
||||
|
@ -3297,7 +3328,11 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
if (definition.hasFixed()) {
|
||||
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, buildJson(definition.getFixed()), null).addStyle("color: darkgreen")));
|
||||
String s = buildJson(definition.getFixed());
|
||||
String link = null;
|
||||
if (Utilities.isAbsoluteUrl(s))
|
||||
link = pkp.getLinkForUrl(corePath, s);
|
||||
c.getPieces().add(checkForNoChange(definition.getFixed(), gen.new Piece(link, s, null).addStyle("color: darkgreen")));
|
||||
} else if (definition.hasPattern()) {
|
||||
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")));
|
||||
|
@ -3427,13 +3462,37 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
|
||||
private boolean isDataType(String value) {
|
||||
StructureDefinition sd = context.fetchTypeDefinition(value);
|
||||
return sd != null && sd.getKind() == StructureDefinitionKind.COMPLEXTYPE;
|
||||
if (sd == null) // might be running before all SDs are available
|
||||
return Utilities.existsInList(value, "Address", "Age", "Annotation", "Attachment", "CodeableConcept", "Coding", "ContactPoint", "Count", "Distance", "Duration", "HumanName", "Identifier", "Money", "Period", "Quantity", "Range", "Ratio", "Reference", "SampledData", "Signature", "Timing",
|
||||
"ContactDetail", "Contributor", "DataRequirement", "Expression", "ParameterDefinition", "RelatedArtifact", "TriggerDefinition", "UsageContext");
|
||||
else
|
||||
return sd.getKind() == StructureDefinitionKind.COMPLEXTYPE && sd.getDerivation() == TypeDerivationRule.SPECIALIZATION;
|
||||
}
|
||||
|
||||
private boolean isConstrainedDataType(String value) {
|
||||
StructureDefinition sd = context.fetchTypeDefinition(value);
|
||||
if (sd == null) // might be running before all SDs are available
|
||||
return Utilities.existsInList(value, "SimpleQuantity", "MoneyQuantity");
|
||||
else
|
||||
return sd.getKind() == StructureDefinitionKind.COMPLEXTYPE && sd.getDerivation() == TypeDerivationRule.CONSTRAINT;
|
||||
}
|
||||
|
||||
private String baseType(String value) {
|
||||
StructureDefinition sd = context.fetchTypeDefinition(value);
|
||||
if (sd != null) // might be running before all SDs are available
|
||||
return sd.getType();
|
||||
if (Utilities.existsInList(value, "SimpleQuantity", "MoneyQuantity"))
|
||||
return "Quantity";
|
||||
throw new Error("Internal error - type not known "+value);
|
||||
}
|
||||
|
||||
|
||||
public boolean isPrimitive(String value) {
|
||||
StructureDefinition sd = context.fetchTypeDefinition(value);
|
||||
return sd != null && sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE;
|
||||
if (sd == null) // might be running before all SDs are available
|
||||
return Utilities.existsInList(value, "base64Binary", "boolean", "canonical", "code", "date", "dateTime", "decimal", "id", "instant", "integer", "markdown", "oid", "positiveInt", "string", "time", "unsignedInt", "uri", "url", "uuid");
|
||||
else
|
||||
return sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE;
|
||||
}
|
||||
|
||||
// private static String listStructures(StructureDefinition p) {
|
||||
|
@ -3692,24 +3751,24 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
// what we have to check for here is running off the base profile into a data type profile
|
||||
ElementDefinition ed = cmp.snapshot.get(child.getBaseIndex());
|
||||
ElementDefinitionComparer ccmp;
|
||||
if (ed.getType().isEmpty() || isAbstract(ed.getType().get(0).getCode()) || ed.getType().get(0).getCode().equals(ed.getPath())) {
|
||||
if (ed.getType().isEmpty() || isAbstract(ed.getType().get(0).getWorkingCode()) || ed.getType().get(0).getWorkingCode().equals(ed.getPath())) {
|
||||
ccmp = new ElementDefinitionComparer(true, cmp.snapshot, cmp.base, cmp.prefixLength, cmp.name);
|
||||
} else if (ed.getType().get(0).getCode().equals("Extension") && child.getSelf().getType().size() == 1 && child.getSelf().getType().get(0).hasProfile()) {
|
||||
} else if (ed.getType().get(0).getWorkingCode().equals("Extension") && child.getSelf().getType().size() == 1 && child.getSelf().getType().get(0).hasProfile()) {
|
||||
StructureDefinition profile = context.fetchResource(StructureDefinition.class, child.getSelf().getType().get(0).getProfile().get(0).getValue());
|
||||
if (profile==null)
|
||||
ccmp = null; // this might happen before everything is loaded. And we don't so much care about sot order in this case
|
||||
else
|
||||
ccmp = new ElementDefinitionComparer(true, profile.getSnapshot().getElement(), ed.getType().get(0).getCode(), child.getSelf().getPath().length(), cmp.name);
|
||||
} else if (ed.getType().size() == 1 && !ed.getType().get(0).getCode().equals("*")) {
|
||||
StructureDefinition profile = context.fetchResource(StructureDefinition.class, sdNs(ed.getType().get(0).getCode()));
|
||||
ccmp = new ElementDefinitionComparer(true, profile.getSnapshot().getElement(), ed.getType().get(0).getWorkingCode(), child.getSelf().getPath().length(), cmp.name);
|
||||
} else if (ed.getType().size() == 1 && !ed.getType().get(0).getWorkingCode().equals("*")) {
|
||||
StructureDefinition profile = context.fetchResource(StructureDefinition.class, sdNs(ed.getType().get(0).getWorkingCode()));
|
||||
if (profile==null)
|
||||
throw new FHIRException("Unable to resolve profile " + sdNs(ed.getType().get(0).getCode()) + " in element " + ed.getPath());
|
||||
ccmp = new ElementDefinitionComparer(false, profile.getSnapshot().getElement(), ed.getType().get(0).getCode(), child.getSelf().getPath().length(), cmp.name);
|
||||
throw new FHIRException("Unable to resolve profile " + sdNs(ed.getType().get(0).getWorkingCode()) + " in element " + ed.getPath());
|
||||
ccmp = new ElementDefinitionComparer(false, profile.getSnapshot().getElement(), ed.getType().get(0).getWorkingCode(), child.getSelf().getPath().length(), cmp.name);
|
||||
} else if (child.getSelf().getType().size() == 1) {
|
||||
StructureDefinition profile = context.fetchResource(StructureDefinition.class, sdNs(child.getSelf().getType().get(0).getCode()));
|
||||
StructureDefinition profile = context.fetchResource(StructureDefinition.class, sdNs(child.getSelf().getType().get(0).getWorkingCode()));
|
||||
if (profile==null)
|
||||
throw new FHIRException("Unable to resolve profile " + sdNs(ed.getType().get(0).getCode()) + " in element " + ed.getPath());
|
||||
ccmp = new ElementDefinitionComparer(false, profile.getSnapshot().getElement(), child.getSelf().getType().get(0).getCode(), child.getSelf().getPath().length(), cmp.name);
|
||||
throw new FHIRException("Unable to resolve profile " + sdNs(ed.getType().get(0).getWorkingCode()) + " in element " + ed.getPath());
|
||||
ccmp = new ElementDefinitionComparer(false, profile.getSnapshot().getElement(), child.getSelf().getType().get(0).getWorkingCode(), child.getSelf().getPath().length(), cmp.name);
|
||||
} else if (ed.getPath().endsWith("[x]") && !child.getSelf().getPath().endsWith("[x]")) {
|
||||
String edLastNode = ed.getPath().replaceAll("(.*\\.)*(.*)", "$2");
|
||||
String childLastNode = child.getSelf().getPath().replaceAll("(.*\\.)*(.*)", "$2");
|
||||
|
@ -3720,27 +3779,27 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
if (sd == null)
|
||||
throw new Error("Unable to find profile '"+p+"' at "+ed.getId());
|
||||
ccmp = new ElementDefinitionComparer(false, sd.getSnapshot().getElement(), p, child.getSelf().getPath().length(), cmp.name);
|
||||
} else if (child.getSelf().hasType() && child.getSelf().getType().get(0).getCode().equals("Reference")) {
|
||||
} else if (child.getSelf().hasType() && child.getSelf().getType().get(0).getWorkingCode().equals("Reference")) {
|
||||
for (TypeRefComponent t: child.getSelf().getType()) {
|
||||
if (!t.getCode().equals("Reference")) {
|
||||
if (!t.getWorkingCode().equals("Reference")) {
|
||||
throw new Error("Can't have children on an element with a polymorphic type - you must slice and constrain the types first (sortElements: "+ed.getPath()+":"+typeCode(ed.getType())+")");
|
||||
}
|
||||
}
|
||||
StructureDefinition profile = context.fetchResource(StructureDefinition.class, sdNs(ed.getType().get(0).getCode()));
|
||||
ccmp = new ElementDefinitionComparer(false, profile.getSnapshot().getElement(), ed.getType().get(0).getCode(), child.getSelf().getPath().length(), cmp.name);
|
||||
} else if (!child.getSelf().hasType() && ed.getType().get(0).getCode().equals("Reference")) {
|
||||
StructureDefinition profile = context.fetchResource(StructureDefinition.class, sdNs(ed.getType().get(0).getWorkingCode()));
|
||||
ccmp = new ElementDefinitionComparer(false, profile.getSnapshot().getElement(), ed.getType().get(0).getWorkingCode(), child.getSelf().getPath().length(), cmp.name);
|
||||
} else if (!child.getSelf().hasType() && ed.getType().get(0).getWorkingCode().equals("Reference")) {
|
||||
for (TypeRefComponent t: ed.getType()) {
|
||||
if (!t.getCode().equals("Reference")) {
|
||||
if (!t.getWorkingCode().equals("Reference")) {
|
||||
throw new Error("Not handled yet (sortElements: "+ed.getPath()+":"+typeCode(ed.getType())+")");
|
||||
}
|
||||
}
|
||||
StructureDefinition profile = context.fetchResource(StructureDefinition.class, sdNs(ed.getType().get(0).getCode()));
|
||||
ccmp = new ElementDefinitionComparer(false, profile.getSnapshot().getElement(), ed.getType().get(0).getCode(), child.getSelf().getPath().length(), cmp.name);
|
||||
StructureDefinition profile = context.fetchResource(StructureDefinition.class, sdNs(ed.getType().get(0).getWorkingCode()));
|
||||
ccmp = new ElementDefinitionComparer(false, profile.getSnapshot().getElement(), ed.getType().get(0).getWorkingCode(), child.getSelf().getPath().length(), cmp.name);
|
||||
} else {
|
||||
// this is allowed if we only profile the extensions
|
||||
StructureDefinition profile = context.fetchResource(StructureDefinition.class, sdNs("Element"));
|
||||
if (profile==null)
|
||||
throw new FHIRException("Unable to resolve profile " + sdNs(ed.getType().get(0).getCode()) + " in element " + ed.getPath());
|
||||
throw new FHIRException("Unable to resolve profile " + sdNs(ed.getType().get(0).getWorkingCode()) + " in element " + ed.getPath());
|
||||
ccmp = new ElementDefinitionComparer(false, profile.getSnapshot().getElement(), "Element", child.getSelf().getPath().length(), cmp.name);
|
||||
// throw new Error("Not handled yet (sortElements: "+ed.getPath()+":"+typeCode(ed.getType())+")");
|
||||
}
|
||||
|
@ -3842,7 +3901,7 @@ public class ProfileUtilities extends TranslatingUtilities {
|
|||
if (!structure.hasSnapshot())
|
||||
throw new DefinitionException("needs a snapshot");
|
||||
|
||||
XLSXWriter xlsx = new XLSXWriter(dest, structure, asXml);
|
||||
XLSXWriter xlsx = new XLSXWriter(dest, structure, asXml, hideMustSupportFalse);
|
||||
|
||||
for (ElementDefinition child : structure.getSnapshot().getElement()) {
|
||||
xlsx.processElement(child);
|
||||
|
|
|
@ -34,6 +34,7 @@ import org.apache.commons.lang3.tuple.ImmutablePair;
|
|||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r4.context.IWorkerContext;
|
||||
import org.hl7.fhir.r4.model.Constants;
|
||||
import org.hl7.fhir.r4.model.DomainResource;
|
||||
import org.hl7.fhir.r4.model.ElementDefinition;
|
||||
import org.hl7.fhir.r4.model.Enumerations;
|
||||
|
@ -568,7 +569,7 @@ public class ShExGenerator {
|
|||
private String genTypeRef(StructureDefinition sd, ElementDefinition ed, String id, ElementDefinition.TypeRefComponent typ) {
|
||||
|
||||
if(typ.hasProfile()) {
|
||||
if(typ.getCode().equals("Reference"))
|
||||
if(typ.getWorkingCode().equals("Reference"))
|
||||
return genReference("", typ);
|
||||
else if(ProfileUtilities.getChildList(sd, ed).size() > 0) {
|
||||
// inline anonymous type - give it a name and factor it out
|
||||
|
@ -581,13 +582,8 @@ public class ShExGenerator {
|
|||
return simpleElement(sd, ed, ref);
|
||||
}
|
||||
|
||||
} else if (typ.getCodeElement().getExtensionsByUrl(ToolingExtensions.EXT_RDF_TYPE).size() > 0) {
|
||||
String xt = null;
|
||||
try {
|
||||
xt = typ.getCodeElement().getExtensionString(ToolingExtensions.EXT_RDF_TYPE);
|
||||
} catch (FHIRException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else if (typ.getWorkingCode().startsWith(Constants.NS_SYSTEM_TYPE)) {
|
||||
String xt = typ.getWorkingCode();
|
||||
// TODO: Remove the next line when the type of token gets switched to string
|
||||
// TODO: Add a rdf-type entry for valueInteger to xsd:integer (instead of int)
|
||||
ST td_entry = tmplt(PRIMITIVE_ELEMENT_DEFN_TEMPLATE).add("typ",
|
||||
|
@ -612,16 +608,16 @@ public class ShExGenerator {
|
|||
td_entry.add("facets", facets.toString());
|
||||
return td_entry.render();
|
||||
|
||||
} else if (typ.getCode() == null) {
|
||||
} else if (typ.getWorkingCode() == null) {
|
||||
ST primitive_entry = tmplt(PRIMITIVE_ELEMENT_DEFN_TEMPLATE);
|
||||
primitive_entry.add("typ", "xsd:string");
|
||||
return primitive_entry.render();
|
||||
|
||||
} else if(typ.getCode().equals("xhtml")) {
|
||||
} else if(typ.getWorkingCode().equals("xhtml")) {
|
||||
return tmplt(XHTML_TYPE_TEMPLATE).render();
|
||||
} else {
|
||||
datatypes.add(typ.getCode());
|
||||
return simpleElement(sd, ed, typ.getCode());
|
||||
datatypes.add(typ.getWorkingCode());
|
||||
return simpleElement(sd, ed, typ.getWorkingCode());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -653,8 +649,8 @@ public class ShExGenerator {
|
|||
* @return ShEx equivalent
|
||||
*/
|
||||
private String genAltEntry(String id, ElementDefinition.TypeRefComponent typ) {
|
||||
if(!typ.getCode().equals("Reference"))
|
||||
throw new AssertionError("We do not handle " + typ.getCode() + " alternatives");
|
||||
if(!typ.getWorkingCode().equals("Reference"))
|
||||
throw new AssertionError("We do not handle " + typ.getWorkingCode() + " alternatives");
|
||||
|
||||
return genReference(id, typ);
|
||||
}
|
||||
|
@ -685,7 +681,7 @@ public class ShExGenerator {
|
|||
private String genChoiceEntry(StructureDefinition sd, ElementDefinition ed, String id, String base, ElementDefinition.TypeRefComponent typ) {
|
||||
ST shex_choice_entry = tmplt(ELEMENT_TEMPLATE);
|
||||
|
||||
String ext = typ.getCode();
|
||||
String ext = typ.getWorkingCode();
|
||||
shex_choice_entry.add("id", "fhir:" + base+Character.toUpperCase(ext.charAt(0)) + ext.substring(1) + " ");
|
||||
shex_choice_entry.add("card", "");
|
||||
shex_choice_entry.add("defn", genTypeRef(sd, ed, id, typ));
|
||||
|
@ -745,7 +741,7 @@ public class ShExGenerator {
|
|||
String[] els = typ.getProfile().get(0).getValue().split("/");
|
||||
return els[els.length - 1];
|
||||
} else {
|
||||
return typ.getCode();
|
||||
return typ.getWorkingCode();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -355,7 +355,7 @@ public class XmlSchemaGenerator {
|
|||
throw new Error("Common ancester not found at "+edc.getPath());
|
||||
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
|
||||
for (TypeRefComponent t : edc.getType()) {
|
||||
b.append(getQN(sd, edc, t.getCode(), true).toString());
|
||||
b.append(getQN(sd, edc, t.getWorkingCode(), true).toString());
|
||||
}
|
||||
|
||||
String name = tailDot(edc.getPath());
|
||||
|
@ -376,8 +376,8 @@ public class XmlSchemaGenerator {
|
|||
} else for (TypeRefComponent t : edc.getType()) {
|
||||
String name = tailDot(edc.getPath());
|
||||
if (edc.getType().size() > 1)
|
||||
name = name + Utilities.capitalize(t.getCode());
|
||||
QName qn = getQN(sd, edc, t.getCode(), true);
|
||||
name = name + Utilities.capitalize(t.getWorkingCode());
|
||||
QName qn = getQN(sd, edc, t.getWorkingCode(), true);
|
||||
String min = String.valueOf(edc.getMin());
|
||||
String max = edc.getMax();
|
||||
if ("*".equals(max))
|
||||
|
@ -436,13 +436,13 @@ public class XmlSchemaGenerator {
|
|||
}
|
||||
|
||||
private StructureDefinition getCommonAncestor(List<TypeRefComponent> type) throws FHIRException {
|
||||
StructureDefinition sd = library.get(type.get(0).getCode());
|
||||
StructureDefinition sd = library.get(type.get(0).getWorkingCode());
|
||||
if (sd == null)
|
||||
throw new FHIRException("Unable to find definition for "+type.get(0).getCode());
|
||||
throw new FHIRException("Unable to find definition for "+type.get(0).getWorkingCode());
|
||||
for (int i = 1; i < type.size(); i++) {
|
||||
StructureDefinition t = library.get(type.get(i).getCode());
|
||||
StructureDefinition t = library.get(type.get(i).getWorkingCode());
|
||||
if (t == null)
|
||||
throw new FHIRException("Unable to find definition for "+type.get(i).getCode());
|
||||
throw new FHIRException("Unable to find definition for "+type.get(i).getWorkingCode());
|
||||
sd = getCommonAncestor(sd, t);
|
||||
}
|
||||
return sd;
|
||||
|
@ -520,10 +520,11 @@ public class XmlSchemaGenerator {
|
|||
// if (!max.equals("1"))
|
||||
// throw new FHIRException("Illegal cardinality \""+max+"\" for attribute "+edc.getPath());
|
||||
|
||||
if (Utilities.isAbsoluteUrl(t.getCode()))
|
||||
throw new FHIRException("Only FHIR primitive types are supported for attributes ("+t.getCode()+")");
|
||||
String tc = t.getWorkingCode();
|
||||
if (Utilities.isAbsoluteUrl(tc))
|
||||
throw new FHIRException("Only FHIR primitive types are supported for attributes ("+tc+")");
|
||||
String typeNs = namespaces.get("http://hl7.org/fhir");
|
||||
String type = t.getCode();
|
||||
String type = tc;
|
||||
|
||||
w(" <xs:attribute name=\""+name+"\" use=\""+(min.equals("0") || edc.hasFixed() || edc.hasDefaultValue() ? "optional" : "required")+"\" type=\""+typeNs+":"+type+(typeNs.equals("fhir") ? "-primitive" : "")+"\""+
|
||||
(edc.hasFixed() ? " fixed=\""+edc.getFixed().primitiveValue()+"\"" : "")+(edc.hasDefaultValue() && !edc.hasFixed() ? " default=\""+edc.getDefaultValue().primitiveValue()+"\"" : "")+"");
|
||||
|
|
|
@ -501,7 +501,7 @@ public abstract class BaseWorkerContext implements IWorkerContext {
|
|||
if (implySystem)
|
||||
pIn.addParameter().setName("implySystem").setValue(new BooleanType(true));
|
||||
if (options != null)
|
||||
updateParameters(options, pIn);
|
||||
setTerminologyOptions(options, pIn);
|
||||
res = validateOnServer(vs, pIn);
|
||||
} catch (Exception e) {
|
||||
res = new ValidationResult(IssueSeverity.ERROR, e.getMessage() == null ? e.getClass().getName() : e.getMessage()).setTxLink(txLog == null ? null : txLog.getLastId());
|
||||
|
@ -511,8 +511,9 @@ public abstract class BaseWorkerContext implements IWorkerContext {
|
|||
return res;
|
||||
}
|
||||
|
||||
public void updateParameters(TerminologyServiceOptions options, Parameters pIn) {
|
||||
if (isNotBlank(options.getLanguage())) {
|
||||
private void setTerminologyOptions(TerminologyServiceOptions options, Parameters pIn) {
|
||||
if (options != null) {
|
||||
if (!Utilities.noString(options.getLanguage()))
|
||||
pIn.addParameter("displayLanguage", options.getLanguage());
|
||||
}
|
||||
}
|
||||
|
@ -541,7 +542,7 @@ public abstract class BaseWorkerContext implements IWorkerContext {
|
|||
Parameters pIn = new Parameters();
|
||||
pIn.addParameter().setName("codeableConcept").setValue(code);
|
||||
if (options != null)
|
||||
updateParameters(options, pIn);
|
||||
setTerminologyOptions(options, pIn);
|
||||
res = validateOnServer(vs, pIn);
|
||||
} catch (Exception e) {
|
||||
res = new ValidationResult(IssueSeverity.ERROR, e.getMessage() == null ? e.getClass().getName() : e.getMessage()).setTxLink(txLog.getLastId());
|
||||
|
@ -964,6 +965,7 @@ public abstract class BaseWorkerContext implements IWorkerContext {
|
|||
result.addAll(maps.values());
|
||||
result.addAll(transforms.values());
|
||||
result.addAll(plans.values());
|
||||
result.addAll(questionnaires.values());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -1114,5 +1116,59 @@ public abstract class BaseWorkerContext implements IWorkerContext {
|
|||
return res;
|
||||
}
|
||||
|
||||
public String getLinkForUrl(String corePath, String url) {
|
||||
for (CodeSystem r : codeSystems.values())
|
||||
if (url.equals(r.getUrl()))
|
||||
return r.getUserString("path");
|
||||
|
||||
for (ValueSet r : valueSets.values())
|
||||
if (url.equals(r.getUrl()))
|
||||
return r.getUserString("path");
|
||||
|
||||
for (ConceptMap r : maps.values())
|
||||
if (url.equals(r.getUrl()))
|
||||
return r.getUserString("path");
|
||||
|
||||
for (StructureMap r : transforms.values())
|
||||
if (url.equals(r.getUrl()))
|
||||
return r.getUserString("path");
|
||||
|
||||
for (StructureDefinition r : structures.values())
|
||||
if (url.equals(r.getUrl()))
|
||||
return r.getUserString("path");
|
||||
|
||||
for (ImplementationGuide r : guides.values())
|
||||
if (url.equals(r.getUrl()))
|
||||
return r.getUserString("path");
|
||||
|
||||
for (CapabilityStatement r : capstmts.values())
|
||||
if (url.equals(r.getUrl()))
|
||||
return r.getUserString("path");
|
||||
|
||||
for (SearchParameter r : searchParameters.values())
|
||||
if (url.equals(r.getUrl()))
|
||||
return r.getUserString("path");
|
||||
|
||||
for (Questionnaire r : questionnaires.values())
|
||||
if (url.equals(r.getUrl()))
|
||||
return r.getUserString("path");
|
||||
|
||||
for (OperationDefinition r : operations.values())
|
||||
if (url.equals(r.getUrl()))
|
||||
return r.getUserString("path");
|
||||
|
||||
for (PlanDefinition r : plans.values())
|
||||
if (url.equals(r.getUrl()))
|
||||
return r.getUserString("path");
|
||||
|
||||
if (url.equals("http://loinc.org"))
|
||||
return corePath+"loinc.html";
|
||||
if (url.equals("http://unitsofmeasure.org"))
|
||||
return corePath+"ucum.html";
|
||||
if (url.equals("http://snomed.info/sct"))
|
||||
return corePath+"snomed.html";
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -160,6 +160,11 @@ public interface IWorkerContext {
|
|||
* It's an error if the second form doesn't agree with class_. It's an
|
||||
* error if class_ is null for the last form
|
||||
*
|
||||
* @param resource
|
||||
* @param Reference
|
||||
* @return
|
||||
* @throws FHIRException
|
||||
* @throws Exception
|
||||
*/
|
||||
public <T extends Resource> T fetchResource(Class<T> class_, String uri);
|
||||
public <T extends Resource> T fetchResourceWithException(Class<T> class_, String uri) throws FHIRException;
|
||||
|
@ -262,6 +267,7 @@ public interface IWorkerContext {
|
|||
/**
|
||||
* ValueSet Expansion - see $expand, but resolves the binding first
|
||||
*
|
||||
* @param source
|
||||
* @return
|
||||
* @throws FHIRException
|
||||
*/
|
||||
|
@ -445,4 +451,6 @@ public interface IWorkerContext {
|
|||
public StructureDefinition fetchTypeDefinition(String typeName);
|
||||
|
||||
public void setUcumService(UcumService ucumService);
|
||||
|
||||
public String getLinkForUrl(String corePath, String s);
|
||||
}
|
||||
|
|
|
@ -604,6 +604,14 @@ public class Element extends Base {
|
|||
return getNamedChild(name) != null;
|
||||
}
|
||||
|
||||
public boolean hasChildren(String name) {
|
||||
if (children != null)
|
||||
for (Element child : children)
|
||||
if (child.getName().equals(name))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name+"="+fhirType() + "["+(children == null || hasValue() ? value : Integer.toString(children.size())+" children")+"]";
|
||||
|
|
|
@ -159,22 +159,7 @@ public class JsonParser extends ParserBase {
|
|||
// note that we do not trouble ourselves to maintain the wire format order here - we don't even know what it was anyway
|
||||
// first pass: process the properties
|
||||
for (Property property : properties) {
|
||||
if (property.isChoice()) {
|
||||
for (TypeRefComponent type : property.getDefinition().getType()) {
|
||||
String eName = property.getName().substring(0, property.getName().length()-3) + Utilities.capitalize(type.getCode());
|
||||
if (!isPrimitive(type.getCode()) && object.has(eName)) {
|
||||
parseChildComplex(path, object, context, processed, property, eName);
|
||||
break;
|
||||
} else if (isPrimitive(type.getCode()) && (object.has(eName) || object.has("_"+eName))) {
|
||||
parseChildPrimitive(object, context, processed, property, path, eName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (property.isPrimitive(property.getType(null))) {
|
||||
parseChildPrimitive(object, context, processed, property, path, property.getName());
|
||||
} else if (object.has(property.getName())) {
|
||||
parseChildComplex(path, object, context, processed, property, property.getName());
|
||||
}
|
||||
parseChildItem(path, object, context, processed, property);
|
||||
}
|
||||
|
||||
// second pass: check for things not processed
|
||||
|
@ -187,6 +172,25 @@ public class JsonParser extends ParserBase {
|
|||
}
|
||||
}
|
||||
|
||||
public void parseChildItem(String path, JsonObject object, Element context, Set<String> processed, Property property) {
|
||||
if (property.isChoice()) {
|
||||
for (TypeRefComponent type : property.getDefinition().getType()) {
|
||||
String eName = property.getName().substring(0, property.getName().length()-3) + Utilities.capitalize(type.getWorkingCode());
|
||||
if (!isPrimitive(type.getWorkingCode()) && object.has(eName)) {
|
||||
parseChildComplex(path, object, context, processed, property, eName);
|
||||
break;
|
||||
} else if (isPrimitive(type.getWorkingCode()) && (object.has(eName) || object.has("_"+eName))) {
|
||||
parseChildPrimitive(object, context, processed, property, path, eName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (property.isPrimitive(property.getType(null))) {
|
||||
parseChildPrimitive(object, context, processed, property, path, property.getName());
|
||||
} else if (object.has(property.getName())) {
|
||||
parseChildComplex(path, object, context, processed, property, property.getName());
|
||||
}
|
||||
}
|
||||
|
||||
private void parseChildComplex(String path, JsonObject object, Element context, Set<String> processed, Property property, String name) throws FHIRException {
|
||||
processed.add(name);
|
||||
String npath = path+"/"+property.getName();
|
||||
|
|
|
@ -64,14 +64,14 @@ public class Property {
|
|||
if (definition.getType().size() == 0)
|
||||
return null;
|
||||
else if (definition.getType().size() > 1) {
|
||||
String tn = definition.getType().get(0).getCode();
|
||||
String tn = definition.getType().get(0).getWorkingCode();
|
||||
for (int i = 1; i < definition.getType().size(); i++) {
|
||||
if (!tn.equals(definition.getType().get(i).getCode()))
|
||||
if (!tn.equals(definition.getType().get(i).getWorkingCode()))
|
||||
throw new Error("logic error, gettype when types > 1");
|
||||
}
|
||||
return tn;
|
||||
} else
|
||||
return definition.getType().get(0).getCode();
|
||||
return definition.getType().get(0).getWorkingCode();
|
||||
}
|
||||
|
||||
public String getType(String elementName) {
|
||||
|
@ -114,7 +114,7 @@ public class Property {
|
|||
else
|
||||
return structure.getId();
|
||||
} else
|
||||
return ed.getType().get(0).getCode();
|
||||
return ed.getType().get(0).getWorkingCode();
|
||||
}
|
||||
|
||||
public boolean hasType(String elementName) {
|
||||
|
@ -251,14 +251,14 @@ public class Property {
|
|||
// ok, find the right definitions
|
||||
String t = null;
|
||||
if (ed.getType().size() == 1)
|
||||
t = ed.getType().get(0).getCode();
|
||||
t = ed.getType().get(0).getWorkingCode();
|
||||
else if (ed.getType().size() == 0)
|
||||
throw new Error("types == 0, and no children found on "+getDefinition().getPath());
|
||||
else {
|
||||
t = ed.getType().get(0).getCode();
|
||||
t = ed.getType().get(0).getWorkingCode();
|
||||
boolean all = true;
|
||||
for (TypeRefComponent tr : ed.getType()) {
|
||||
if (!tr.getCode().equals(t)) {
|
||||
if (!tr.getWorkingCode().equals(t)) {
|
||||
all = false;
|
||||
break;
|
||||
}
|
||||
|
@ -271,12 +271,12 @@ public class Property {
|
|||
t = ToolingExtensions.readStringExtension(ed, "http://hl7.org/fhir/StructureDefinition/elementdefinition-defaulttype");
|
||||
boolean ok = false;
|
||||
for (TypeRefComponent tr : ed.getType()) {
|
||||
if (tr.getCode().equals(t))
|
||||
if (tr.getWorkingCode().equals(t))
|
||||
ok = true;
|
||||
if (Utilities.isAbsoluteUrl(tr.getCode())) {
|
||||
StructureDefinition sdt = context.fetchResource(StructureDefinition.class, tr.getCode());
|
||||
if (Utilities.isAbsoluteUrl(tr.getWorkingCode())) {
|
||||
StructureDefinition sdt = context.fetchResource(StructureDefinition.class, tr.getWorkingCode());
|
||||
if (sdt != null && sdt.getType().equals(t)) {
|
||||
url = tr.getCode();
|
||||
url = tr.getWorkingCode();
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
|
@ -295,7 +295,7 @@ public class Property {
|
|||
}
|
||||
if (!"xhtml".equals(t)) {
|
||||
for (TypeRefComponent aType: ed.getType()) {
|
||||
if (aType.getCode().equals(t)) {
|
||||
if (aType.getWorkingCode().equals(t)) {
|
||||
if (aType.hasProfile()) {
|
||||
assert aType.getProfile().size() == 1;
|
||||
url = aType.getProfile().get(0).getValue();
|
||||
|
|
|
@ -59,4 +59,7 @@ public class Constants {
|
|||
public final static String BUILD_ID = "e0e3caf9ba";
|
||||
public final static String DATE = "Thu Dec 13 14:07:26 AEDT 2018";
|
||||
public final static String URI_REGEX = "((http|https)://([A-Za-z0-9\\\\\\.\\:\\%\\$]*\\/)*)?(Account|ActivityDefinition|AdverseEvent|AllergyIntolerance|Appointment|AppointmentResponse|AuditEvent|Basic|Binary|BiologicallyDerivedProduct|BodyStructure|Bundle|CapabilityStatement|CarePlan|CareTeam|CatalogEntry|ChargeItem|ChargeItemDefinition|Claim|ClaimResponse|ClinicalImpression|CodeSystem|Communication|CommunicationRequest|CompartmentDefinition|Composition|ConceptMap|Condition|Consent|Contract|Coverage|CoverageEligibilityRequest|CoverageEligibilityResponse|DetectedIssue|Device|DeviceDefinition|DeviceMetric|DeviceRequest|DeviceUseStatement|DiagnosticReport|DocumentManifest|DocumentReference|EffectEvidenceSynthesis|Encounter|Endpoint|EnrollmentRequest|EnrollmentResponse|EpisodeOfCare|EventDefinition|Evidence|EvidenceVariable|ExampleScenario|ExplanationOfBenefit|FamilyMemberHistory|Flag|Goal|GraphDefinition|Group|GuidanceResponse|HealthcareService|ImagingStudy|Immunization|ImmunizationEvaluation|ImmunizationRecommendation|ImplementationGuide|InsurancePlan|Invoice|Library|Linkage|List|Location|Measure|MeasureReport|Media|Medication|MedicationAdministration|MedicationDispense|MedicationKnowledge|MedicationRequest|MedicationStatement|MedicinalProduct|MedicinalProductAuthorization|MedicinalProductContraindication|MedicinalProductIndication|MedicinalProductIngredient|MedicinalProductInteraction|MedicinalProductManufactured|MedicinalProductPackaged|MedicinalProductPharmaceutical|MedicinalProductUndesirableEffect|MessageDefinition|MessageHeader|MolecularSequence|NamingSystem|NutritionOrder|Observation|ObservationDefinition|OperationDefinition|OperationOutcome|Organization|OrganizationAffiliation|Patient|PaymentNotice|PaymentReconciliation|Person|PlanDefinition|Practitioner|PractitionerRole|Procedure|Provenance|Questionnaire|QuestionnaireResponse|RelatedPerson|RequestGroup|ResearchDefinition|ResearchElementDefinition|ResearchStudy|ResearchSubject|RiskAssessment|RiskEvidenceSynthesis|Schedule|SearchParameter|ServiceRequest|Slot|Specimen|SpecimenDefinition|StructureDefinition|StructureMap|Subscription|Substance|SubstanceNucleicAcid|SubstancePolymer|SubstanceProtein|SubstanceReferenceInformation|SubstanceSourceMaterial|SubstanceSpecification|SupplyDelivery|SupplyRequest|Task|TerminologyCapabilities|TestReport|TestScript|ValueSet|VerificationResult|VisionPrescription)\\/[A-Za-z0-9\\-\\.]{1,64}(\\/_history\\/[A-Za-z0-9\\-\\.]{1,64})?";
|
||||
public final static String LOCAL_REF_REGEX = "(Account|ActivityDefinition|AdverseEvent|AllergyIntolerance|Appointment|AppointmentResponse|AuditEvent|Basic|Binary|BiologicallyDerivedProduct|BodyStructure|Bundle|CapabilityStatement|CarePlan|CareTeam|CatalogEntry|ChargeItem|ChargeItemDefinition|Claim|ClaimResponse|ClinicalImpression|CodeSystem|Communication|CommunicationRequest|CompartmentDefinition|Composition|ConceptMap|Condition|Consent|Contract|Coverage|CoverageEligibilityRequest|CoverageEligibilityResponse|DetectedIssue|Device|DeviceDefinition|DeviceMetric|DeviceRequest|DeviceUseStatement|DiagnosticReport|DocumentManifest|DocumentReference|EffectEvidenceSynthesis|Encounter|Endpoint|EnrollmentRequest|EnrollmentResponse|EpisodeOfCare|EventDefinition|Evidence|EvidenceVariable|ExampleScenario|ExplanationOfBenefit|FamilyMemberHistory|Flag|Goal|GraphDefinition|Group|GuidanceResponse|HealthcareService|ImagingStudy|Immunization|ImmunizationEvaluation|ImmunizationRecommendation|ImplementationGuide|InsurancePlan|Invoice|Library|Linkage|List|Location|Measure|MeasureReport|Media|Medication|MedicationAdministration|MedicationDispense|MedicationKnowledge|MedicationRequest|MedicationStatement|MedicinalProduct|MedicinalProductAuthorization|MedicinalProductContraindication|MedicinalProductIndication|MedicinalProductIngredient|MedicinalProductInteraction|MedicinalProductManufactured|MedicinalProductPackaged|MedicinalProductPharmaceutical|MedicinalProductUndesirableEffect|MessageDefinition|MessageHeader|MolecularSequence|NamingSystem|NutritionOrder|Observation|ObservationDefinition|OperationDefinition|OperationOutcome|Organization|OrganizationAffiliation|Patient|PaymentNotice|PaymentReconciliation|Person|PlanDefinition|Practitioner|PractitionerRole|Procedure|Provenance|Questionnaire|QuestionnaireResponse|RelatedPerson|RequestGroup|ResearchDefinition|ResearchElementDefinition|ResearchStudy|ResearchSubject|RiskAssessment|RiskEvidenceSynthesis|Schedule|SearchParameter|ServiceRequest|Slot|Specimen|SpecimenDefinition|StructureDefinition|StructureMap|Subscription|Substance|SubstanceNucleicAcid|SubstancePolymer|SubstanceProtein|SubstanceReferenceInformation|SubstanceSourceMaterial|SubstanceSpecification|SupplyDelivery|SupplyRequest|Task|TerminologyCapabilities|TestReport|TestScript|ValueSet|VerificationResult|VisionPrescription)\\/[A-Za-z0-9\\-\\.]{1,64}";
|
||||
public final static String NS_SYSTEM_TYPE = "http://hl7.org/fhirpath/System.";
|
||||
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ import org.hl7.fhir.instance.model.api.IBaseDatatypeElement;
|
|||
import org.hl7.fhir.instance.model.api.ICompositeType;
|
||||
import org.hl7.fhir.r4.model.Enumerations.BindingStrength;
|
||||
import org.hl7.fhir.r4.model.Enumerations.BindingStrengthEnumFactory;
|
||||
import org.hl7.fhir.r4.utils.ToolingExtensions;
|
||||
// added from java-adornments.txt:
|
||||
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
|
@ -2256,6 +2257,50 @@ public class ElementDefinition extends BackboneType implements ICompositeType {
|
|||
return Utilities.existsInList(getCode(), "Reference", "canonical");
|
||||
}
|
||||
|
||||
/**
|
||||
* This code checks for the system prefix and returns the FHIR type
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getWorkingCode() {
|
||||
if (hasExtension(ToolingExtensions.EXT_FHIR_TYPE))
|
||||
return getExtensionString(ToolingExtensions.EXT_FHIR_TYPE);
|
||||
if (!hasCodeElement())
|
||||
return null;
|
||||
if (getCodeElement().hasExtension(ToolingExtensions.EXT_XML_TYPE)) {
|
||||
String s = getCodeElement().getExtensionString(ToolingExtensions.EXT_XML_TYPE);
|
||||
if ("xsd:gYear OR xsd:gYearMonth OR xsd:date OR xsd:dateTime".equals(s))
|
||||
return "dateTime";
|
||||
if ("xsd:gYear OR xsd:gYearMonth OR xsd:date".equals(s))
|
||||
return "date";
|
||||
if ("xsd:dateTime".equals(s))
|
||||
return "instant";
|
||||
if ("xsd:token".equals(s))
|
||||
return "code";
|
||||
if ("xsd:boolean".equals(s))
|
||||
return "boolean";
|
||||
if ("xsd:string".equals(s))
|
||||
return "string";
|
||||
if ("xsd:time".equals(s))
|
||||
return "time";
|
||||
if ("xsd:int".equals(s))
|
||||
return "integer";
|
||||
if ("xsd:decimal OR xsd:double".equals(s))
|
||||
return "decimal";
|
||||
if ("xsd:base64Binary".equals(s))
|
||||
return "base64Binary";
|
||||
if ("xsd:positiveInteger".equals(s))
|
||||
return "positiveInt";
|
||||
if ("xsd:nonNegativeInteger".equals(s))
|
||||
return "unsignedInt";
|
||||
if ("xsd:anyURI".equals(s))
|
||||
return "uri";
|
||||
|
||||
throw new Error("Unknown xml type '"+s+"'");
|
||||
}
|
||||
return getCode();
|
||||
}
|
||||
|
||||
// end addition
|
||||
}
|
||||
|
||||
|
|
|
@ -1975,6 +1975,42 @@ public class Questionnaire extends MetadataResource {
|
|||
|
||||
}
|
||||
|
||||
public QuestionnaireItemComponent getQuestion(String linkId) {
|
||||
if (linkId == null)
|
||||
return null;
|
||||
for (QuestionnaireItemComponent i : getItem()) {
|
||||
if (i.getLinkId().equals(linkId))
|
||||
return i;
|
||||
QuestionnaireItemComponent t = i.getQuestion(linkId);
|
||||
if (t != null)
|
||||
return t;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public QuestionnaireItemComponent getCommonGroup(QuestionnaireItemComponent q1, QuestionnaireItemComponent q2) {
|
||||
if (q1 == null || q2 == null)
|
||||
return null;
|
||||
for (QuestionnaireItemComponent i : getItem()) {
|
||||
QuestionnaireItemComponent t = i.getCommonGroup(q1, q2);
|
||||
if (t != null)
|
||||
return t;
|
||||
}
|
||||
if (containsQuestion(q1) && containsQuestion(q2))
|
||||
return this;
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean containsQuestion(QuestionnaireItemComponent q) {
|
||||
if (q == this)
|
||||
return true;
|
||||
for (QuestionnaireItemComponent i : getItem()) {
|
||||
if (i.containsQuestion(q))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Block()
|
||||
|
@ -5222,6 +5258,29 @@ public class Questionnaire extends MetadataResource {
|
|||
*/
|
||||
public static final ca.uhn.fhir.rest.gclient.TokenClientParam STATUS = new ca.uhn.fhir.rest.gclient.TokenClientParam(SP_STATUS);
|
||||
|
||||
|
||||
public QuestionnaireItemComponent getQuestion(String linkId) {
|
||||
if (linkId == null)
|
||||
return null;
|
||||
for (QuestionnaireItemComponent i : getItem()) {
|
||||
if (i.getLinkId().equals(linkId))
|
||||
return i;
|
||||
QuestionnaireItemComponent t = i.getQuestion(linkId);
|
||||
if (t != null)
|
||||
return t;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public QuestionnaireItemComponent getCommonGroup(QuestionnaireItemComponent q1, QuestionnaireItemComponent q2) {
|
||||
for (QuestionnaireItemComponent i : getItem()) {
|
||||
QuestionnaireItemComponent t = i.getCommonGroup(q1, q2);
|
||||
if (t != null)
|
||||
return t;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -166,12 +166,12 @@ public class DefinitionNavigator {
|
|||
|
||||
private void loadTypedChildren(TypeRefComponent type) throws DefinitionException {
|
||||
typeOfChildren = null;
|
||||
StructureDefinition sd = context.fetchResource(StructureDefinition.class, /* GF#13465 : this somehow needs to be revisited type.hasProfile() ? type.getProfile() : */ type.getCode());
|
||||
StructureDefinition sd = context.fetchResource(StructureDefinition.class, /* GF#13465 : this somehow needs to be revisited type.hasProfile() ? type.getProfile() : */ type.getWorkingCode());
|
||||
if (sd != null) {
|
||||
DefinitionNavigator dn = new DefinitionNavigator(context, sd, 0, path, names, sd.getType());
|
||||
typeChildren = dn.children();
|
||||
} else
|
||||
throw new DefinitionException("Unable to find definition for "+type.getCode()+(type.hasProfile() ? "("+type.getProfile()+")" : ""));
|
||||
throw new DefinitionException("Unable to find definition for "+type.getWorkingCode()+(type.hasProfile() ? "("+type.getProfile()+")" : ""));
|
||||
typeOfChildren = type;
|
||||
}
|
||||
|
||||
|
|
|
@ -234,6 +234,11 @@ public class FHIRPathEngine {
|
|||
public Base resolveReference(Object appContext, String url) throws FHIRException;
|
||||
|
||||
public boolean conformsToProfile(Object appContext, Base item, String url) throws FHIRException;
|
||||
|
||||
/*
|
||||
* return the value set referenced by the url, which has been used in memberOf()
|
||||
*/
|
||||
public ValueSet resolveValueSet(Object appContext, String url);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1164,10 +1169,10 @@ public class FHIRPathEngine {
|
|||
work = work2;
|
||||
else if (last.getOperation() == Operation.Is || last.getOperation() == Operation.As) {
|
||||
work2 = executeTypeName(context, focus, next, false);
|
||||
work = operate(work, last.getOperation(), work2);
|
||||
work = operate(context, work, last.getOperation(), work2);
|
||||
} else {
|
||||
work2 = execute(context, focus, next, true);
|
||||
work = operate(work, last.getOperation(), work2);
|
||||
work = operate(context, work, last.getOperation(), work2);
|
||||
// System.out.println("Result of {'"+last.toString()+" "+last.getOperation().toCode()+" "+next.toString()+"'}: "+focus.toString());
|
||||
}
|
||||
last = next;
|
||||
|
@ -1390,7 +1395,7 @@ public class FHIRPathEngine {
|
|||
}
|
||||
|
||||
|
||||
private List<Base> operate(List<Base> left, Operation operation, List<Base> right) throws FHIRException {
|
||||
private List<Base> operate(ExecutionContext context, List<Base> left, Operation operation, List<Base> right) throws FHIRException {
|
||||
switch (operation) {
|
||||
case Equals: return opEquals(left, right);
|
||||
case Equivalent: return opEquivalent(left, right);
|
||||
|
@ -1402,7 +1407,7 @@ public class FHIRPathEngine {
|
|||
case GreaterOrEqual: return opGreaterOrEqual(left, right);
|
||||
case Union: return opUnion(left, right);
|
||||
case In: return opIn(left, right);
|
||||
case MemberOf: return opMemberOf(left, right);
|
||||
case MemberOf: return opMemberOf(context, left, right);
|
||||
case Contains: return opContains(left, right);
|
||||
case Or: return opOr(left, right);
|
||||
case And: return opAnd(left, right);
|
||||
|
@ -1874,9 +1879,9 @@ public class FHIRPathEngine {
|
|||
return new ArrayList<Base>();
|
||||
}
|
||||
|
||||
private List<Base> opMemberOf(List<Base> left, List<Base> right) throws FHIRException {
|
||||
private List<Base> opMemberOf(ExecutionContext context, List<Base> left, List<Base> right) throws FHIRException {
|
||||
boolean ans = false;
|
||||
ValueSet vs = worker.fetchResource(ValueSet.class, right.get(0).primitiveValue());
|
||||
ValueSet vs = hostServices != null ? hostServices.resolveValueSet(context.appInfo, right.get(0).primitiveValue()) : worker.fetchResource(ValueSet.class, right.get(0).primitiveValue());
|
||||
if (vs != null) {
|
||||
for (Base l : left) {
|
||||
if (l.fhirType().equals("code")) {
|
||||
|
@ -3513,8 +3518,10 @@ public class FHIRPathEngine {
|
|||
String st = convertToString(focus.get(0));
|
||||
if (Utilities.noString(st))
|
||||
result.add(new BooleanType(false).noExtensions());
|
||||
else
|
||||
result.add(new BooleanType(st.matches(sw)).noExtensions());
|
||||
else {
|
||||
boolean ok = st.matches(sw);
|
||||
result.add(new BooleanType(ok).noExtensions());
|
||||
}
|
||||
} else
|
||||
result.add(new BooleanType(false).noExtensions());
|
||||
return result;
|
||||
|
@ -3908,6 +3915,9 @@ public class FHIRPathEngine {
|
|||
throw new PathEngineException("No type provided in BuildToolPathEvaluator.getChildTypesByName");
|
||||
if (type.equals("http://hl7.org/fhir/StructureDefinition/xhtml"))
|
||||
return;
|
||||
if (type.startsWith(Constants.NS_SYSTEM_TYPE))
|
||||
return;
|
||||
|
||||
if (type.equals(TypeDetails.FP_SimpleTypeInfo)) {
|
||||
getSimpleTypeChildTypesByName(name, result);
|
||||
} else if (type.equals(TypeDetails.FP_ClassInfo)) {
|
||||
|
@ -3999,7 +4009,7 @@ public class FHIRPathEngine {
|
|||
else
|
||||
for (TypeRefComponent t : ed.getDefinition().getType()) {
|
||||
if (Utilities.noString(t.getCode())) {
|
||||
if (Utilities.existsInList(ed.getDefinition().getId(), "Element.id", "Extension.url"))
|
||||
if (Utilities.existsInList(ed.getDefinition().getId(), "Element.id", "Extension.url") || Utilities.existsInList(ed.getDefinition().getBase().getPath(), "Resource.id", "Element.id", "Extension.url"))
|
||||
result.addType(TypeDetails.FP_NS, "string");
|
||||
break; // throw new PathEngineException("Illegal reference to primitive value attribute @ "+path);
|
||||
}
|
||||
|
@ -4317,5 +4327,10 @@ public class FHIRPathEngine {
|
|||
public TerminologyServiceOptions getTerminologyServiceOptions() {
|
||||
return terminologyServiceOptions;
|
||||
}
|
||||
|
||||
|
||||
public IWorkerContext getWorker() {
|
||||
return worker;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -297,18 +297,18 @@ public class GraphQLSchemaGenerator {
|
|||
|
||||
private void generateProperty(List<StringBuilder> list, StringBuilder b, String typeName, StructureDefinition sd, ElementDefinition child, TypeRefComponent typeDetails, boolean suffix, ElementDefinition cr, String mode, String suffixS) throws IOException {
|
||||
if (isPrimitive(typeDetails)) {
|
||||
String n = getGqlname(typeDetails.getCode());
|
||||
String n = getGqlname(typeDetails.getWorkingCode());
|
||||
b.append(" ");
|
||||
b.append(tail(child.getPath(), suffix));
|
||||
if (suffix)
|
||||
b.append(Utilities.capitalize(typeDetails.getCode()));
|
||||
b.append(Utilities.capitalize(typeDetails.getWorkingCode()));
|
||||
b.append(": ");
|
||||
b.append(n);
|
||||
if (!child.getPath().endsWith(".id")) {
|
||||
b.append(" _");
|
||||
b.append(tail(child.getPath(), suffix));
|
||||
if (suffix)
|
||||
b.append(Utilities.capitalize(typeDetails.getCode()));
|
||||
b.append(Utilities.capitalize(typeDetails.getWorkingCode()));
|
||||
if (!child.getMax().equals("1"))
|
||||
b.append(": [ElementBase]\r\n");
|
||||
else
|
||||
|
@ -319,11 +319,11 @@ public class GraphQLSchemaGenerator {
|
|||
b.append(" ");
|
||||
b.append(tail(child.getPath(), suffix));
|
||||
if (suffix)
|
||||
b.append(Utilities.capitalize(typeDetails.getCode()));
|
||||
b.append(Utilities.capitalize(typeDetails.getWorkingCode()));
|
||||
b.append(": ");
|
||||
if (!child.getMax().equals("1"))
|
||||
b.append("[");
|
||||
String type = typeDetails.getCode();
|
||||
String type = typeDetails.getWorkingCode();
|
||||
if (cr != null)
|
||||
b.append(generateInnerType(list, sd, typeName, cr, mode, suffixS));
|
||||
else if (Utilities.existsInList(type, "Element", "BackboneElement"))
|
||||
|
@ -366,7 +366,7 @@ public class GraphQLSchemaGenerator {
|
|||
}
|
||||
|
||||
private boolean isPrimitive(TypeRefComponent type) {
|
||||
String typeName = type.getCode();
|
||||
String typeName = type.getWorkingCode();
|
||||
StructureDefinition sd = context.fetchTypeDefinition(typeName);
|
||||
if (sd == null)
|
||||
return false;
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.hl7.fhir.r4.model.ExpressionNode;
|
|||
import org.hl7.fhir.r4.model.Resource;
|
||||
import org.hl7.fhir.r4.model.Tuple;
|
||||
import org.hl7.fhir.r4.model.TypeDetails;
|
||||
import org.hl7.fhir.r4.model.ValueSet;
|
||||
import org.hl7.fhir.r4.utils.FHIRPathEngine.ExpressionNodeWithOffset;
|
||||
import org.hl7.fhir.r4.utils.FHIRPathEngine.IEvaluationContext;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
|
@ -417,4 +418,13 @@ public class LiquidEngine implements IEvaluationContext {
|
|||
return conformsToProfile(ctxt.externalContext, item, url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet resolveValueSet(Object appContext, String url) {
|
||||
LiquidEngineContext ctxt = (LiquidEngineContext) appContext;
|
||||
if (externalHostServices != null)
|
||||
return externalHostServices.resolveValueSet(ctxt.externalContext, url);
|
||||
else
|
||||
return engine.getWorker().fetchResource(ValueSet.class, url);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -77,6 +77,7 @@ import org.hl7.fhir.utilities.xml.XmlGenerator;
|
|||
import org.w3c.dom.Element;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
@ -307,29 +308,29 @@ public class NarrativeGenerator implements INarrativeGenerator {
|
|||
}
|
||||
|
||||
private interface PropertyWrapper {
|
||||
String getName();
|
||||
boolean hasValues();
|
||||
List<BaseWrapper> getValues();
|
||||
String getTypeCode();
|
||||
String getDefinition();
|
||||
int getMinCardinality();
|
||||
int getMaxCardinality();
|
||||
StructureDefinition getStructure();
|
||||
BaseWrapper value();
|
||||
public String getName();
|
||||
public boolean hasValues();
|
||||
public List<BaseWrapper> getValues();
|
||||
public String getTypeCode();
|
||||
public String getDefinition();
|
||||
public int getMinCardinality();
|
||||
public int getMaxCardinality();
|
||||
public StructureDefinition getStructure();
|
||||
public BaseWrapper value();
|
||||
}
|
||||
|
||||
private interface ResourceWrapper {
|
||||
List<ResourceWrapper> getContained();
|
||||
String getId();
|
||||
XhtmlNode getNarrative() throws IOException, FHIRException;
|
||||
String getName();
|
||||
List<PropertyWrapper> children();
|
||||
public List<ResourceWrapper> getContained();
|
||||
public String getId();
|
||||
public XhtmlNode getNarrative() throws FHIRFormatError, IOException, FHIRException;
|
||||
public String getName();
|
||||
public List<PropertyWrapper> children();
|
||||
}
|
||||
|
||||
private interface BaseWrapper {
|
||||
Base getBase() throws IOException, FHIRException;
|
||||
List<PropertyWrapper> children();
|
||||
PropertyWrapper getChildByName(String tail);
|
||||
public Base getBase() throws UnsupportedEncodingException, IOException, FHIRException;
|
||||
public List<PropertyWrapper> children();
|
||||
public PropertyWrapper getChildByName(String tail);
|
||||
}
|
||||
|
||||
private class BaseWrapperElement implements BaseWrapper {
|
||||
|
@ -348,7 +349,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Base getBase() throws IOException, FHIRException {
|
||||
public Base getBase() throws UnsupportedEncodingException, IOException, FHIRException {
|
||||
if (type == null || type.equals("Resource") || type.equals("BackboneElement") || type.equals("Element"))
|
||||
return null;
|
||||
|
||||
|
@ -421,9 +422,9 @@ public class NarrativeGenerator implements INarrativeGenerator {
|
|||
if (definition.getType().isEmpty())
|
||||
return null;
|
||||
if (definition.getType().size() == 1) {
|
||||
if (definition.getType().get(0).getCode().equals("Element") || definition.getType().get(0).getCode().equals("BackboneElement"))
|
||||
if (definition.getType().get(0).getWorkingCode().equals("Element") || definition.getType().get(0).getWorkingCode().equals("BackboneElement"))
|
||||
return null;
|
||||
return definition.getType().get(0).getCode();
|
||||
return definition.getType().get(0).getWorkingCode();
|
||||
}
|
||||
String t = e.getNodeName().substring(tail(definition.getPath()).length()-3);
|
||||
|
||||
|
@ -442,7 +443,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
|
|||
public String getTypeCode() {
|
||||
if (definition == null || definition.getType().size() != 1)
|
||||
throw new Error("not handled");
|
||||
return definition.getType().get(0).getCode();
|
||||
return definition.getType().get(0).getWorkingCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -496,7 +497,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Base getBase() throws IOException, FHIRException {
|
||||
public Base getBase() throws UnsupportedEncodingException, IOException, FHIRException {
|
||||
if (type == null || type.equals("Resource") || type.equals("BackboneElement") || type.equals("Element"))
|
||||
return null;
|
||||
|
||||
|
@ -699,7 +700,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public XhtmlNode getNarrative() throws IOException, FHIRException {
|
||||
public XhtmlNode getNarrative() throws FHIRFormatError, IOException, FHIRException {
|
||||
Element txt = XMLUtil.getNamedChild(wrapped, "text");
|
||||
if (txt == null)
|
||||
return null;
|
||||
|
@ -1058,7 +1059,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
|
|||
return b;
|
||||
}
|
||||
|
||||
private void generateByProfile(Element eres, StructureDefinition profile, Element ee, List<ElementDefinition> allElements, ElementDefinition defn, List<ElementDefinition> children, XhtmlNode x, String path, boolean showCodeDetails) throws FHIRException, IOException {
|
||||
private void generateByProfile(Element eres, StructureDefinition profile, Element ee, List<ElementDefinition> allElements, ElementDefinition defn, List<ElementDefinition> children, XhtmlNode x, String path, boolean showCodeDetails) throws FHIRException, UnsupportedEncodingException, IOException {
|
||||
|
||||
ResourceWrapperElement resw = new ResourceWrapperElement(eres, profile);
|
||||
BaseWrapperElement base = new BaseWrapperElement(ee, null, profile, profile.getSnapshot().getElement().get(0));
|
||||
|
@ -1066,11 +1067,11 @@ public class NarrativeGenerator implements INarrativeGenerator {
|
|||
}
|
||||
|
||||
|
||||
private void generateByProfile(Resource res, StructureDefinition profile, Base e, List<ElementDefinition> allElements, ElementDefinition defn, List<ElementDefinition> children, XhtmlNode x, String path, boolean showCodeDetails, ResourceContext rc) throws FHIRException, IOException {
|
||||
private void generateByProfile(Resource res, StructureDefinition profile, Base e, List<ElementDefinition> allElements, ElementDefinition defn, List<ElementDefinition> children, XhtmlNode x, String path, boolean showCodeDetails, ResourceContext rc) throws FHIRException, UnsupportedEncodingException, IOException {
|
||||
generateByProfile(new ResourceWrapperDirect(res), profile, new BaseWrapperDirect(e), allElements, defn, children, x, path, showCodeDetails, 0, rc);
|
||||
}
|
||||
|
||||
private void generateByProfile(ResourceWrapper res, StructureDefinition profile, BaseWrapper e, List<ElementDefinition> allElements, ElementDefinition defn, List<ElementDefinition> children, XhtmlNode x, String path, boolean showCodeDetails, int indent, ResourceContext rc) throws FHIRException, IOException {
|
||||
private void generateByProfile(ResourceWrapper res, StructureDefinition profile, BaseWrapper e, List<ElementDefinition> allElements, ElementDefinition defn, List<ElementDefinition> children, XhtmlNode x, String path, boolean showCodeDetails, int indent, ResourceContext rc) throws FHIRException, UnsupportedEncodingException, IOException {
|
||||
if (children.isEmpty()) {
|
||||
renderLeaf(res, e, defn, x, false, showCodeDetails, readDisplayHints(defn), path, indent, rc);
|
||||
} else {
|
||||
|
@ -1160,7 +1161,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
|
|||
grandChildren.removeAll(toRemove);
|
||||
}
|
||||
|
||||
private List<PropertyWrapper> splitExtensions(StructureDefinition profile, List<PropertyWrapper> children) throws IOException, FHIRException {
|
||||
private List<PropertyWrapper> splitExtensions(StructureDefinition profile, List<PropertyWrapper> children) throws UnsupportedEncodingException, IOException, FHIRException {
|
||||
List<PropertyWrapper> results = new ArrayList<PropertyWrapper>();
|
||||
Map<String, PropertyWrapper> map = new HashMap<String, PropertyWrapper>();
|
||||
for (PropertyWrapper p : children)
|
||||
|
@ -1196,7 +1197,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
|
|||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private boolean isDefaultValue(Map<String, String> displayHints, List<BaseWrapper> list) throws IOException, FHIRException {
|
||||
private boolean isDefaultValue(Map<String, String> displayHints, List<BaseWrapper> list) throws UnsupportedEncodingException, IOException, FHIRException {
|
||||
if (list.size() != 1)
|
||||
return false;
|
||||
if (list.get(0).getBase() instanceof PrimitiveType)
|
||||
|
@ -1207,7 +1208,9 @@ public class NarrativeGenerator implements INarrativeGenerator {
|
|||
|
||||
private boolean isDefault(Map<String, String> displayHints, PrimitiveType primitiveType) {
|
||||
String v = primitiveType.asStringValue();
|
||||
return !Utilities.noString(v) && displayHints.containsKey("default") && v.equals(displayHints.get("default"));
|
||||
if (!Utilities.noString(v) && displayHints.containsKey("default") && v.equals(displayHints.get("default")))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean exemptFromRendering(ElementDefinition child) {
|
||||
|
@ -1215,13 +1218,16 @@ public class NarrativeGenerator implements INarrativeGenerator {
|
|||
return false;
|
||||
if ("Composition.subject".equals(child.getPath()))
|
||||
return true;
|
||||
return "Composition.section".equals(child.getPath());
|
||||
if ("Composition.section".equals(child.getPath()))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean renderAsList(ElementDefinition child) {
|
||||
if (child.getType().size() == 1) {
|
||||
String t = child.getType().get(0).getCode();
|
||||
return t.equals("Address") || t.equals("Reference");
|
||||
String t = child.getType().get(0).getWorkingCode();
|
||||
if (t.equals("Address") || t.equals("Reference"))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -1231,7 +1237,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
|
|||
tr.td().b().addText(Utilities.capitalize(tail(e.getPath())));
|
||||
}
|
||||
|
||||
private void addColumnValues(ResourceWrapper res, XhtmlNode tr, List<ElementDefinition> grandChildren, BaseWrapper v, boolean showCodeDetails, Map<String, String> displayHints, String path, int indent, ResourceContext rc) throws FHIRException, IOException {
|
||||
private void addColumnValues(ResourceWrapper res, XhtmlNode tr, List<ElementDefinition> grandChildren, BaseWrapper v, boolean showCodeDetails, Map<String, String> displayHints, String path, int indent, ResourceContext rc) throws FHIRException, UnsupportedEncodingException, IOException {
|
||||
for (ElementDefinition e : grandChildren) {
|
||||
PropertyWrapper p = v.getChildByName(e.getPath().substring(e.getPath().lastIndexOf(".")+1));
|
||||
if (p == null || p.getValues().size() == 0 || p.getValues().get(0) == null)
|
||||
|
@ -1274,7 +1280,9 @@ public class NarrativeGenerator implements INarrativeGenerator {
|
|||
//we can tell if e is a primitive because it has types
|
||||
if (e.getType().isEmpty())
|
||||
return false;
|
||||
return e.getType().size() != 1 || !isBase(e.getType().get(0).getCode());
|
||||
if (e.getType().size() == 1 && isBase(e.getType().get(0).getWorkingCode()))
|
||||
return false;
|
||||
return true;
|
||||
// return !e.getType().isEmpty()
|
||||
}
|
||||
|
||||
|
@ -1291,7 +1299,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
|
|||
return null;
|
||||
}
|
||||
|
||||
private void renderLeaf(ResourceWrapper res, BaseWrapper ew, ElementDefinition defn, XhtmlNode x, boolean title, boolean showCodeDetails, Map<String, String> displayHints, String path, int indent, ResourceContext rc) throws FHIRException, IOException {
|
||||
private void renderLeaf(ResourceWrapper res, BaseWrapper ew, ElementDefinition defn, XhtmlNode x, boolean title, boolean showCodeDetails, Map<String, String> displayHints, String path, int indent, ResourceContext rc) throws FHIRException, UnsupportedEncodingException, IOException {
|
||||
if (ew == null)
|
||||
return;
|
||||
|
||||
|
@ -1397,7 +1405,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean displayLeaf(ResourceWrapper res, BaseWrapper ew, ElementDefinition defn, XhtmlNode x, String name, boolean showCodeDetails, ResourceContext rc) throws FHIRException, IOException {
|
||||
private boolean displayLeaf(ResourceWrapper res, BaseWrapper ew, ElementDefinition defn, XhtmlNode x, String name, boolean showCodeDetails, ResourceContext rc) throws FHIRException, UnsupportedEncodingException, IOException {
|
||||
if (ew == null)
|
||||
return false;
|
||||
Base e = ew.getBase();
|
||||
|
@ -1551,7 +1559,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
|
|||
return s + (!p.hasEnd() ? "(ongoing)" : p.getEndElement().toHumanDisplay());
|
||||
}
|
||||
|
||||
private void generateResourceSummary(XhtmlNode x, ResourceWrapper res, boolean textAlready, boolean showCodeDetails, ResourceContext rc) throws FHIRException, IOException {
|
||||
private void generateResourceSummary(XhtmlNode x, ResourceWrapper res, boolean textAlready, boolean showCodeDetails, ResourceContext rc) throws FHIRException, UnsupportedEncodingException, IOException {
|
||||
if (!textAlready) {
|
||||
XhtmlNode div = res.getNarrative();
|
||||
if (div != null) {
|
||||
|
@ -1597,8 +1605,9 @@ public class NarrativeGenerator implements INarrativeGenerator {
|
|||
if (child.getMustSupport())
|
||||
return true;
|
||||
if (child.getType().size() == 1) {
|
||||
String t = child.getType().get(0).getCode();
|
||||
return !t.equals("Address") && !t.equals("Contact") && !t.equals("Reference") && !t.equals("Uri") && !t.equals("Url") && !t.equals("Canonical");
|
||||
String t = child.getType().get(0).getWorkingCode();
|
||||
if (t.equals("Address") || t.equals("Contact") || t.equals("Reference") || t.equals("Uri") || t.equals("Url") || t.equals("Canonical"))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -4026,7 +4035,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
|
|||
tr = tbl.tr();
|
||||
tr.td().addText(p.getUse().toString());
|
||||
tr.td().addText(path+p.getName());
|
||||
tr.td().addText(p.getMin() +".."+p.getMax());
|
||||
tr.td().addText(Integer.toString(p.getMin())+".."+p.getMax());
|
||||
XhtmlNode td = tr.td();
|
||||
StructureDefinition sd = context.fetchTypeDefinition(p.getType());
|
||||
if (sd == null)
|
||||
|
@ -4044,8 +4053,6 @@ public class NarrativeGenerator implements INarrativeGenerator {
|
|||
}
|
||||
} else
|
||||
td.ah(sd.getUserString("path")).tx(p.hasType() ? p.getType() : "");
|
||||
|
||||
|
||||
if (p.hasSearchType()) {
|
||||
td.br();
|
||||
td.tx("(");
|
||||
|
@ -4263,7 +4270,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
|
|||
for (SectionComponent section : sections) {
|
||||
node.hr();
|
||||
if (section.hasTitleElement())
|
||||
node.addTag("h"+ level).addText(section.getTitle());
|
||||
node.addTag("h"+Integer.toString(level)).addText(section.getTitle());
|
||||
// else if (section.hasCode())
|
||||
// node.addTag("h"+Integer.toString(level)).addText(displayCodeableConcept(section.getCode()));
|
||||
|
||||
|
@ -4532,7 +4539,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
|
|||
if (be.hasResource() && be.getResource().hasId())
|
||||
root.an(be.getResource().getResourceType().name().toLowerCase() + "_" + be.getResource().getId());
|
||||
root.hr();
|
||||
root.para().addText("Entry "+ i +(be.hasFullUrl() ? " - Full URL = " + be.getFullUrl() : ""));
|
||||
root.para().addText("Entry "+Integer.toString(i)+(be.hasFullUrl() ? " - Full URL = " + be.getFullUrl() : ""));
|
||||
if (be.hasRequest())
|
||||
renderRequest(root, be.getRequest());
|
||||
if (be.hasSearch())
|
||||
|
|
|
@ -114,18 +114,18 @@ public class ProtoBufGenerator {
|
|||
if (ed.getType().size() != 1)
|
||||
fld.type = "Unknown";
|
||||
else {
|
||||
StructureDefinition td = context.fetchTypeDefinition(ed.getTypeFirstRep().getCode());
|
||||
StructureDefinition td = context.fetchTypeDefinition(ed.getTypeFirstRep().getWorkingCode());
|
||||
if (td == null)
|
||||
fld.type = "Unresolved";
|
||||
else if (td.getKind() == StructureDefinitionKind.PRIMITIVETYPE) {
|
||||
fld.type = protoTypeForFhirType(ed.getTypeFirstRep().getCode());
|
||||
fld.type = protoTypeForFhirType(ed.getTypeFirstRep().getWorkingCode());
|
||||
fld = new Field();
|
||||
fld.name = tail(ed.getPath())+"Extra";
|
||||
fld.repeating = (!ed.getMax().equals("1"));
|
||||
fld.type = "Primitive";
|
||||
message.fields.add(fld);
|
||||
} else
|
||||
fld.type = ed.getTypeFirstRep().getCode();
|
||||
fld.type = ed.getTypeFirstRep().getWorkingCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -316,11 +316,11 @@ public class QuestionnaireBuilder {
|
|||
}
|
||||
|
||||
private boolean isAbstractType(List<TypeRefComponent> type) {
|
||||
return type.size() == 1 && (type.get(0).getCode().equals("Element") || type.get(0).getCode().equals("BackboneElement"));
|
||||
return type.size() == 1 && (type.get(0).getWorkingCode().equals("Element") || type.get(0).getWorkingCode().equals("BackboneElement"));
|
||||
}
|
||||
|
||||
private boolean isInlineDataType(List<TypeRefComponent> type) {
|
||||
return type.size() == 1 && !Utilities.existsInList(type.get(0).getCode(), "code", "string", "id", "oid", "markdown", "uri", "boolean", "decimal", "dateTime", "date", "instant", "time", "CodeableConcept", "Period", "Ratio",
|
||||
return type.size() == 1 && !Utilities.existsInList(type.get(0).getWorkingCode(), "code", "string", "id", "oid", "markdown", "uri", "boolean", "decimal", "dateTime", "date", "instant", "time", "CodeableConcept", "Period", "Ratio",
|
||||
"HumanName", "Address", "ContactPoint", "Identifier", "integer", "positiveInt", "unsignedInt", "Coding", "Quantity", "Count", "Age", "Duration",
|
||||
"Distance", "Money", "Money", "Reference", "Duration", "base64Binary", "Attachment", "Age", "Range", "Timing", "Annotation", "SampledData", "Extension",
|
||||
"SampledData", "Narrative", "Resource", "Meta", "url", "canonical");
|
||||
|
@ -330,7 +330,7 @@ public class QuestionnaireBuilder {
|
|||
String n = tail(child.getPath());
|
||||
String t = "";
|
||||
if (!element.getType().isEmpty())
|
||||
t = element.getType().get(0).getCode();
|
||||
t = element.getType().get(0).getWorkingCode();
|
||||
|
||||
// we don't generate questions for the base stuff in every element
|
||||
if (t.equals("Resource") && (n.equals("text") || n.equals("language") || n.equals("contained")))
|
||||
|
@ -385,7 +385,7 @@ public class QuestionnaireBuilder {
|
|||
else
|
||||
ToolingExtensions.addFlyOver(group, element.getDefinition());
|
||||
|
||||
if (element.getType().size() > 1 || element.getType().get(0).getCode().equals("*")) {
|
||||
if (element.getType().size() > 1 || element.getType().get(0).getWorkingCode().equals("*")) {
|
||||
List<TypeRefComponent> types = expandTypeList(element.getType());
|
||||
Questionnaire.QuestionnaireItemComponent q = addQuestion(group, QuestionnaireItemType.CHOICE, element.getPath(), "_type", "type", null, makeTypeList(profile, types, element.getPath()));
|
||||
for (TypeRefComponent t : types) {
|
||||
|
@ -410,7 +410,7 @@ public class QuestionnaireBuilder {
|
|||
for (TypeRefComponent t : types) {
|
||||
if (t.hasProfile())
|
||||
result.add(t);
|
||||
else if (t.getCode().equals("*")) {
|
||||
else if (t.getWorkingCode().equals("*")) {
|
||||
result.add(new TypeRefComponent().setCode("integer"));
|
||||
result.add(new TypeRefComponent().setCode("decimal"));
|
||||
result.add(new TypeRefComponent().setCode("dateTime"));
|
||||
|
@ -459,8 +459,8 @@ public class QuestionnaireBuilder {
|
|||
}
|
||||
} else if (!t.hasProfile()) {
|
||||
ValueSetExpansionContainsComponent cc = vs.getExpansion().addContains();
|
||||
cc.setCode(t.getCode());
|
||||
cc.setDisplay(t.getCode());
|
||||
cc.setCode(t.getWorkingCode());
|
||||
cc.setDisplay(t.getWorkingCode());
|
||||
cc.setSystem("http://hl7.org/fhir/data-types");
|
||||
} else for (UriType u : t.getProfile()) {
|
||||
ProfileUtilities pu = new ProfileUtilities(context, null, null);
|
||||
|
@ -514,7 +514,7 @@ public class QuestionnaireBuilder {
|
|||
cc.setCode(t.getProfile().get(0).getValue());
|
||||
cc.setSystem("http://hl7.org/fhir/resource-types");
|
||||
} else {
|
||||
cc.setCode(t.getCode());
|
||||
cc.setCode(t.getWorkingCode());
|
||||
cc.setSystem("http://hl7.org/fhir/data-types");
|
||||
}
|
||||
}
|
||||
|
@ -529,7 +529,7 @@ public class QuestionnaireBuilder {
|
|||
}
|
||||
|
||||
private boolean instanceOf(TypeRefComponent t, Element obj) {
|
||||
if (t.getCode().equals("Reference")) {
|
||||
if (t.getWorkingCode().equals("Reference")) {
|
||||
if (!(obj instanceof Reference)) {
|
||||
return false;
|
||||
} else {
|
||||
|
@ -542,7 +542,7 @@ public class QuestionnaireBuilder {
|
|||
else
|
||||
return true;
|
||||
}
|
||||
} else if (t.getCode().equals("Quantity")) {
|
||||
} else if (t.getWorkingCode().equals("Quantity")) {
|
||||
return obj instanceof Quantity;
|
||||
} else
|
||||
throw new NotImplementedException("Not Done Yet");
|
||||
|
@ -703,77 +703,78 @@ public class QuestionnaireBuilder {
|
|||
}
|
||||
|
||||
private boolean isPrimitive(TypeRefComponent t) {
|
||||
String code = t.getCode();
|
||||
String code = t.getWorkingCode();
|
||||
StructureDefinition sd = context.fetchTypeDefinition(code);
|
||||
return sd != null && sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE;
|
||||
}
|
||||
|
||||
private void processDataType(StructureDefinition profile, QuestionnaireItemComponent group, ElementDefinition element, String path, TypeRefComponent t, List<QuestionnaireResponse.QuestionnaireResponseItemComponent> answerGroups, List<ElementDefinition> parents) throws FHIRException {
|
||||
if (t.getCode().equals("code"))
|
||||
String tc = t.getWorkingCode();
|
||||
if (tc.equals("code"))
|
||||
addCodeQuestions(group, element, path, answerGroups);
|
||||
else if (Utilities.existsInList(t.getCode(), "string", "id", "oid", "uuid", "markdown"))
|
||||
else if (Utilities.existsInList(tc, "string", "id", "oid", "uuid", "markdown"))
|
||||
addStringQuestions(group, element, path, answerGroups);
|
||||
else if (Utilities.existsInList(t.getCode(), "uri", "url", "canonical"))
|
||||
else if (Utilities.existsInList(tc, "uri", "url", "canonical"))
|
||||
addUriQuestions(group, element, path, answerGroups);
|
||||
else if (t.getCode().equals("boolean"))
|
||||
else if (tc.equals("boolean"))
|
||||
addBooleanQuestions(group, element, path, answerGroups);
|
||||
else if (t.getCode().equals("decimal"))
|
||||
else if (tc.equals("decimal"))
|
||||
addDecimalQuestions(group, element, path, answerGroups);
|
||||
else if (t.getCode().equals("dateTime") || t.getCode().equals("date"))
|
||||
else if (tc.equals("dateTime") || tc.equals("date"))
|
||||
addDateTimeQuestions(group, element, path, answerGroups);
|
||||
else if (t.getCode().equals("instant"))
|
||||
else if (tc.equals("instant"))
|
||||
addInstantQuestions(group, element, path, answerGroups);
|
||||
else if (t.getCode().equals("time"))
|
||||
else if (tc.equals("time"))
|
||||
addTimeQuestions(group, element, path, answerGroups);
|
||||
else if (t.getCode().equals("CodeableConcept"))
|
||||
else if (tc.equals("CodeableConcept"))
|
||||
addCodeableConceptQuestions(group, element, path, answerGroups);
|
||||
else if (t.getCode().equals("Period"))
|
||||
else if (tc.equals("Period"))
|
||||
addPeriodQuestions(group, element, path, answerGroups);
|
||||
else if (t.getCode().equals("Ratio"))
|
||||
else if (tc.equals("Ratio"))
|
||||
addRatioQuestions(group, element, path, answerGroups);
|
||||
else if (t.getCode().equals("HumanName"))
|
||||
else if (tc.equals("HumanName"))
|
||||
addHumanNameQuestions(group, element, path, answerGroups);
|
||||
else if (t.getCode().equals("Address"))
|
||||
else if (tc.equals("Address"))
|
||||
addAddressQuestions(group, element, path, answerGroups);
|
||||
else if (t.getCode().equals("ContactPoint"))
|
||||
else if (tc.equals("ContactPoint"))
|
||||
addContactPointQuestions(group, element, path, answerGroups);
|
||||
else if (t.getCode().equals("Identifier"))
|
||||
else if (tc.equals("Identifier"))
|
||||
addIdentifierQuestions(group, element, path, answerGroups);
|
||||
else if (t.getCode().equals("integer") || t.getCode().equals("positiveInt") || t.getCode().equals("unsignedInt") )
|
||||
else if (tc.equals("integer") || tc.equals("positiveInt") || tc.equals("unsignedInt") )
|
||||
addIntegerQuestions(group, element, path, answerGroups);
|
||||
else if (t.getCode().equals("Coding"))
|
||||
else if (tc.equals("Coding"))
|
||||
addCodingQuestions(group, element, path, answerGroups);
|
||||
else if (Utilities.existsInList(t.getCode(), "Quantity", "Count", "Age", "Duration", "Distance", "Money"))
|
||||
else if (Utilities.existsInList(tc, "Quantity", "Count", "Age", "Duration", "Distance", "Money"))
|
||||
addQuantityQuestions(group, element, path, answerGroups);
|
||||
else if (t.getCode().equals("Money"))
|
||||
else if (tc.equals("Money"))
|
||||
addMoneyQuestions(group, element, path, answerGroups);
|
||||
else if (t.getCode().equals("Reference"))
|
||||
else if (tc.equals("Reference"))
|
||||
addReferenceQuestions(group, element, path, t.getTargetProfile(), answerGroups);
|
||||
else if (t.getCode().equals("Duration"))
|
||||
else if (tc.equals("Duration"))
|
||||
addDurationQuestions(group, element, path, answerGroups);
|
||||
else if (t.getCode().equals("base64Binary"))
|
||||
else if (tc.equals("base64Binary"))
|
||||
addBinaryQuestions(group, element, path, answerGroups);
|
||||
else if (t.getCode().equals("Attachment"))
|
||||
else if (tc.equals("Attachment"))
|
||||
addAttachmentQuestions(group, element, path, answerGroups);
|
||||
else if (t.getCode().equals("Age"))
|
||||
else if (tc.equals("Age"))
|
||||
addAgeQuestions(group, element, path, answerGroups);
|
||||
else if (t.getCode().equals("Range"))
|
||||
else if (tc.equals("Range"))
|
||||
addRangeQuestions(group, element, path, answerGroups);
|
||||
else if (t.getCode().equals("Timing"))
|
||||
else if (tc.equals("Timing"))
|
||||
addTimingQuestions(group, element, path, answerGroups);
|
||||
else if (t.getCode().equals("Annotation"))
|
||||
else if (tc.equals("Annotation"))
|
||||
addAnnotationQuestions(group, element, path, answerGroups);
|
||||
else if (t.getCode().equals("SampledData"))
|
||||
else if (tc.equals("SampledData"))
|
||||
addSampledDataQuestions(group, element, path, answerGroups);
|
||||
else if (t.getCode().equals("Extension")) {
|
||||
else if (tc.equals("Extension")) {
|
||||
if (t.hasProfile())
|
||||
addExtensionQuestions(profile, group, element, path, t.getProfile().get(0).getValue(), answerGroups, parents);
|
||||
} else if (t.getCode().equals("SampledData"))
|
||||
} else if (tc.equals("SampledData"))
|
||||
addSampledDataQuestions(group, element, path, answerGroups);
|
||||
else if (!t.getCode().equals("Narrative") && !t.getCode().equals("Resource") && !t.getCode().equals("Meta") && !t.getCode().equals("Signature")) {
|
||||
StructureDefinition sd = context.fetchTypeDefinition(t.getCode());
|
||||
else if (!tc.equals("Narrative") && !tc.equals("Resource") && !tc.equals("Meta") && !tc.equals("Signature")) {
|
||||
StructureDefinition sd = context.fetchTypeDefinition(tc);
|
||||
if (sd == null)
|
||||
throw new NotImplementedException("Unhandled Data Type: "+t.getCode()+" on element "+element.getPath());
|
||||
throw new NotImplementedException("Unhandled Data Type: "+tc+" on element "+element.getPath());
|
||||
buildGroup(group, sd, sd.getSnapshot().getElementFirstRep(), parents, answerGroups);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -363,7 +363,7 @@ public class ResourceUtilities {
|
|||
private static String renderType(TypeRefComponent type) {
|
||||
if (type == null || type.isEmpty())
|
||||
return "";
|
||||
return type.getCode();
|
||||
return type.getWorkingCode();
|
||||
}
|
||||
|
||||
public static void renderContactPoint(StringBuilder b, ContactPoint cp) {
|
||||
|
|
|
@ -217,6 +217,11 @@ public class StructureMapUtilities {
|
|||
throw new NotImplementedException("Not done yet (FFHIRPathHostServices.conformsToProfile), when item is element");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet resolveValueSet(Object appContext, String url) {
|
||||
throw new Error("Not Implemented Yet");
|
||||
}
|
||||
|
||||
}
|
||||
private IWorkerContext worker;
|
||||
private FHIRPathEngine fpe;
|
||||
|
@ -2447,7 +2452,7 @@ public class StructureMapUtilities {
|
|||
for (TypeRefComponent tr : element.getDefinition().getType()) {
|
||||
if (!tr.hasCode())
|
||||
throw new Error("Rule \""+ruleId+"\": Element has no type");
|
||||
ProfiledType pt = new ProfiledType(tr.getCode());
|
||||
ProfiledType pt = new ProfiledType(tr.getWorkingCode());
|
||||
if (tr.hasProfile())
|
||||
pt.addProfiles(tr.getProfile());
|
||||
if (element.getDefinition().hasBinding())
|
||||
|
@ -2705,11 +2710,11 @@ public class StructureMapUtilities {
|
|||
|
||||
|
||||
private String checkType(String t, Property pvb, List<String> profiles) throws FHIRException {
|
||||
if (pvb.getDefinition().getType().size() == 1 && isCompatibleType(t, pvb.getDefinition().getType().get(0).getCode()) && profilesMatch(profiles, pvb.getDefinition().getType().get(0).getProfile()))
|
||||
if (pvb.getDefinition().getType().size() == 1 && isCompatibleType(t, pvb.getDefinition().getType().get(0).getWorkingCode()) && profilesMatch(profiles, pvb.getDefinition().getType().get(0).getProfile()))
|
||||
return null;
|
||||
for (TypeRefComponent tr : pvb.getDefinition().getType()) {
|
||||
if (isCompatibleType(t, tr.getCode()))
|
||||
return tr.getCode(); // note what is returned - the base type, not the inferred mapping type
|
||||
if (isCompatibleType(t, tr.getWorkingCode()))
|
||||
return tr.getWorkingCode(); // note what is returned - the base type, not the inferred mapping type
|
||||
}
|
||||
throw new FHIRException("The type "+t+" is not compatible with the allowed types for "+pvb.getDefinition().getPath());
|
||||
}
|
||||
|
|
|
@ -105,9 +105,6 @@ public class ToolingExtensions {
|
|||
public static final String EXT_ISSUE_COL = "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-col";
|
||||
public static final String EXT_DISPLAY_HINT = "http://hl7.org/fhir/StructureDefinition/structuredefinition-display-hint";
|
||||
public static final String EXT_REPLACED_BY = "http://hl7.org/fhir/StructureDefinition/valueset-replacedby";
|
||||
public static final String EXT_JSON_TYPE = "http://hl7.org/fhir/StructureDefinition/structuredefinition-json-type";
|
||||
public static final String EXT_RDF_TYPE = "http://hl7.org/fhir/StructureDefinition/structuredefinition-rdf-type";
|
||||
public static final String EXT_XML_TYPE = "http://hl7.org/fhir/StructureDefinition/structuredefinition-xml-type";
|
||||
public static final String EXT_REGEX = "http://hl7.org/fhir/StructureDefinition/regex";
|
||||
public static final String EXT_CONTROL = "http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl";
|
||||
public static final String EXT_MINOCCURS = "http://hl7.org/fhir/StructureDefinition/questionnaire-minOccurs";
|
||||
|
@ -163,6 +160,8 @@ public class ToolingExtensions {
|
|||
public static final String EXT_MAPPING_TGTCARD = "http://hl7.org/fhir/tools/StructureDefinition/conceptmap-target-cardinality";
|
||||
public static final String EXT_PRIVATE_BASE = "http://hl7.org/fhir/tools/";
|
||||
public static final String EXT_ALLOWED_TYPE = "http://hl7.org/fhir/StructureDefinition/operationdefinition-allowed-type";
|
||||
public static final String EXT_FHIR_TYPE = "http://hl7.org/fhir/StructureDefinition/structuredefinition-fhir-type";
|
||||
public static final String EXT_XML_TYPE = "http://hl7.org/fhir/StructureDefinition/structuredefinition-xml-type";
|
||||
|
||||
// specific extension helpers
|
||||
|
||||
|
@ -214,6 +213,16 @@ public class ToolingExtensions {
|
|||
}
|
||||
}
|
||||
|
||||
public static void addCodeExtension(Element e, String url, String content) {
|
||||
if (!StringUtils.isBlank(content)) {
|
||||
Extension ex = getExtension(e, url);
|
||||
if (ex != null)
|
||||
ex.setValue(new CodeType(content));
|
||||
else
|
||||
e.getExtension().add(Factory.newExtension(url, new CodeType(content), true));
|
||||
}
|
||||
}
|
||||
|
||||
public static void addStringExtension(DomainResource e, String url, String content) {
|
||||
if (!StringUtils.isBlank(content)) {
|
||||
Extension ex = getExtension(e, url);
|
||||
|
|
|
@ -143,6 +143,7 @@ public class TypesUtilities {
|
|||
|
||||
// special cases
|
||||
res.add(new WildcardInformation("Dosage", TypeClassification.SPECIAL));
|
||||
res.add(new WildcardInformation("Meta", TypeClassification.SPECIAL));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,18 +32,18 @@ public class ValidationProfileSet {
|
|||
|
||||
public static class ProfileRegistration {
|
||||
private String profile;
|
||||
private boolean error;
|
||||
private boolean errorOnMissing;
|
||||
|
||||
public ProfileRegistration(String profile, boolean error) {
|
||||
public ProfileRegistration(String profile, boolean errorOnMissing) {
|
||||
super();
|
||||
this.profile = profile;
|
||||
this.error = error;
|
||||
this.errorOnMissing = errorOnMissing;
|
||||
}
|
||||
public String getProfile() {
|
||||
return profile;
|
||||
}
|
||||
public boolean isError() {
|
||||
return error;
|
||||
public boolean isErrorOnMissing() {
|
||||
return errorOnMissing;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -230,7 +230,7 @@ public class CSVWriter extends TextStreamWriter {
|
|||
val = o.toString();
|
||||
} else if (o instanceof TypeRefComponent) {
|
||||
TypeRefComponent t = (TypeRefComponent)o;
|
||||
val = t.getCode() + (t.getProfile() == null ? "" : " {" + t.getProfile() + "}") +(t.getTargetProfile() == null ? "" : " {" + t.getTargetProfile() + "}") + (t.getAggregation() == null || t.getAggregation().isEmpty() ? "" : " (" + itemList(t.getAggregation()) + ")");
|
||||
val = t.getWorkingCode() + (t.getProfile() == null ? "" : " {" + t.getProfile() + "}") +(t.getTargetProfile() == null ? "" : " {" + t.getTargetProfile() + "}") + (t.getAggregation() == null || t.getAggregation().isEmpty() ? "" : " (" + itemList(t.getAggregation()) + ")");
|
||||
} else if (o instanceof Coding) {
|
||||
Coding t = (Coding)o;
|
||||
val = (t.getSystem()==null ? "" : t.getSystem()) + (t.getCode()==null ? "" : "#" + t.getCode()) + (t.getDisplay()==null ? "" : " (" + t.getDisplay() + ")");
|
||||
|
|
|
@ -53,8 +53,10 @@ import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
|||
import org.hl7.fhir.r4.formats.IParser.OutputStyle;
|
||||
import org.hl7.fhir.r4.formats.JsonParser;
|
||||
import org.hl7.fhir.r4.formats.XmlParser;
|
||||
import org.hl7.fhir.r4.model.CanonicalType;
|
||||
import org.hl7.fhir.r4.model.Coding;
|
||||
import org.hl7.fhir.r4.model.ElementDefinition;
|
||||
import org.hl7.fhir.r4.model.ElementDefinition.AggregationMode;
|
||||
import org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionConstraintComponent;
|
||||
import org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionMappingComponent;
|
||||
import org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionSlicingDiscriminatorComponent;
|
||||
|
@ -65,6 +67,7 @@ import org.hl7.fhir.r4.model.StructureDefinition;
|
|||
import org.hl7.fhir.r4.model.StructureDefinition.StructureDefinitionMappingComponent;
|
||||
import org.hl7.fhir.r4.model.Type;
|
||||
import org.hl7.fhir.r4.model.UriType;
|
||||
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
|
||||
import org.hl7.fhir.utilities.TextStreamWriter;
|
||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTAutoFilter;
|
||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCustomFilter;
|
||||
|
@ -84,6 +87,7 @@ public class XLSXWriter extends TextStreamWriter {
|
|||
private XmlParser xml = new XmlParser();
|
||||
private JsonParser json = new JsonParser();
|
||||
private boolean asXml;
|
||||
private boolean hideMustSupportFalse;
|
||||
|
||||
private static String[] titles = {
|
||||
"Path", "Slice Name", "Alias(s)", "Label", "Min", "Max", "Must Support?", "Is Modifier?", "Is Summary?", "Type(s)", "Short",
|
||||
|
@ -92,11 +96,12 @@ public class XLSXWriter extends TextStreamWriter {
|
|||
"Slicing Discriminator", "Slicing Description", "Slicing Ordered", "Slicing Rules", "Base Path", "Base Min", "Base Max",
|
||||
"Condition(s)", "Constraint(s)"};
|
||||
|
||||
public XLSXWriter(OutputStream out, StructureDefinition def, boolean asXml) throws UnsupportedEncodingException {
|
||||
public XLSXWriter(OutputStream out, StructureDefinition def, boolean asXml, boolean hideMustSupportFalse) throws UnsupportedEncodingException {
|
||||
super(out);
|
||||
outStream = out;
|
||||
this.asXml = asXml;
|
||||
this.def = def;
|
||||
this.hideMustSupportFalse = hideMustSupportFalse;
|
||||
sheet = wb.createSheet("Elements");
|
||||
styles = createStyles(wb);
|
||||
Row headerRow = sheet.createRow(0);
|
||||
|
@ -155,7 +160,7 @@ public class XLSXWriter extends TextStreamWriter {
|
|||
|
||||
private static CellStyle createBorderedStyle(Workbook wb){
|
||||
BorderStyle thin = BorderStyle.THIN;
|
||||
short black = IndexedColors.BLACK.getIndex();
|
||||
short black = IndexedColors.GREY_50_PERCENT.getIndex();
|
||||
|
||||
CellStyle style = wb.createCellStyle();
|
||||
style.setBorderRight(thin);
|
||||
|
@ -262,7 +267,17 @@ public class XLSXWriter extends TextStreamWriter {
|
|||
val = o.toString();
|
||||
} else if (o instanceof TypeRefComponent) {
|
||||
TypeRefComponent t = (TypeRefComponent)o;
|
||||
val = t.getCode() + (t.getProfile() == null ? "" : " {" + t.getProfile() + "}") +(t.getTargetProfile() == null ? "" : " {" + t.getTargetProfile() + "}") + (t.getAggregation() == null || t.getAggregation().isEmpty() ? "" : " (" + itemList(t.getAggregation()) + ")");
|
||||
val = t.getWorkingCode();
|
||||
if (val == null)
|
||||
val = "";
|
||||
if (val.startsWith("http://hl7.org/fhir/StructureDefinition/"))
|
||||
val = val.substring(40);
|
||||
if (t.hasTargetProfile())
|
||||
val = val+ "(" + canonicalList(t.getTargetProfile()) + ")";
|
||||
if (t.hasProfile())
|
||||
val = val + " {" + canonicalList(t.getProfile()) + "}";
|
||||
if (t.hasAggregation())
|
||||
val = val + " <<" + aggList(t.getAggregation()) + ">>";
|
||||
} else if (o instanceof Coding) {
|
||||
Coding t = (Coding)o;
|
||||
val = (t.getSystem()==null ? "" : t.getSystem()) + (t.getCode()==null ? "" : "#" + t.getCode()) + (t.getDisplay()==null ? "" : " (" + t.getDisplay() + ")");
|
||||
|
@ -285,7 +300,30 @@ public class XLSXWriter extends TextStreamWriter {
|
|||
return s.toString();
|
||||
}
|
||||
|
||||
private String aggList(List<org.hl7.fhir.r4.model.Enumeration<AggregationMode>> list) {
|
||||
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
|
||||
for (org.hl7.fhir.r4.model.Enumeration<AggregationMode> c : list)
|
||||
b.append(c.getValue().toCode());
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
private String canonicalList(List<CanonicalType> list) {
|
||||
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder("|");
|
||||
for (CanonicalType c : list) {
|
||||
String v = c.getValue();
|
||||
if (v.startsWith("http://hl7.org/fhir/StructureDefinition/"))
|
||||
v = v.substring(40);
|
||||
b.append(v);
|
||||
}
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
private String renderType(Type value) throws Exception {
|
||||
if (value == null)
|
||||
return "";
|
||||
if (value.isPrimitive())
|
||||
return value.primitiveValue();
|
||||
|
||||
String s = null;
|
||||
ByteArrayOutputStream bs = new ByteArrayOutputStream();
|
||||
if (asXml) {
|
||||
|
@ -339,6 +377,7 @@ public class XLSXWriter extends TextStreamWriter {
|
|||
}
|
||||
sheet.createFreezePane(2,1);
|
||||
|
||||
if (hideMustSupportFalse) {
|
||||
SheetConditionalFormatting sheetCF = sheet.getSheetConditionalFormatting();
|
||||
String address = "A2:AI" + Math.max(Integer.valueOf(sheet.getLastRowNum()), 2);
|
||||
CellRangeAddress[] regions = {
|
||||
|
@ -378,6 +417,7 @@ public class XLSXWriter extends TextStreamWriter {
|
|||
for (Row row : sheet) {
|
||||
if (row.getRowNum()>0 && (!row.getCell(6).getStringCellValue().equals("Y") || !row.getCell(26).getStringCellValue().isEmpty())) {
|
||||
((XSSFRow) row).getCTRow().setHidden(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
sheet.setActiveCell(new CellAddress(sheet.getRow(1).getCell(0)));
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.hl7.fhir.r4.model.PrimitiveType;
|
|||
import org.hl7.fhir.r4.model.Quantity;
|
||||
import org.hl7.fhir.r4.model.Resource;
|
||||
import org.hl7.fhir.r4.model.TypeDetails;
|
||||
import org.hl7.fhir.r4.model.ValueSet;
|
||||
import org.hl7.fhir.r4.test.utils.TestingUtilities;
|
||||
import org.hl7.fhir.r4.utils.FHIRPathEngine;
|
||||
import org.hl7.fhir.r4.utils.FHIRPathEngine.IEvaluationContext;
|
||||
|
@ -90,6 +91,10 @@ public class FHIRPathTests {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet resolveValueSet(Object appContext, String url) {
|
||||
return TestingUtilities.context().fetchResource(ValueSet.class, url);
|
||||
}
|
||||
}
|
||||
|
||||
private static FHIRPathEngine fp;
|
||||
|
|
|
@ -2,6 +2,7 @@ package org.hl7.fhir.r4.test;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
@ -22,6 +23,7 @@ import org.hl7.fhir.r4.conformance.ProfileUtilities;
|
|||
import org.hl7.fhir.r4.conformance.ProfileUtilities.ProfileKnowledgeProvider;
|
||||
import org.hl7.fhir.r4.context.SimpleWorkerContext;
|
||||
import org.hl7.fhir.r4.formats.IParser.OutputStyle;
|
||||
import org.hl7.fhir.r4.formats.JsonParser;
|
||||
import org.hl7.fhir.r4.formats.XmlParser;
|
||||
import org.hl7.fhir.r4.model.Base;
|
||||
import org.hl7.fhir.r4.model.Coding;
|
||||
|
@ -39,25 +41,142 @@ import org.hl7.fhir.r4.model.TestScript.SetupActionOperationComponent;
|
|||
import org.hl7.fhir.r4.model.TestScript.TestActionComponent;
|
||||
import org.hl7.fhir.r4.model.TestScript.TestScriptFixtureComponent;
|
||||
import org.hl7.fhir.r4.model.TestScript.TestScriptTestComponent;
|
||||
import org.hl7.fhir.r4.test.SnapShotGenerationTests.TestFetchMode;
|
||||
import org.hl7.fhir.r4.test.utils.TestingUtilities;
|
||||
import org.hl7.fhir.r4.model.TypeDetails;
|
||||
import org.hl7.fhir.r4.model.ValueSet;
|
||||
import org.hl7.fhir.r4.utils.CodingUtilities;
|
||||
import org.hl7.fhir.r4.utils.EOperationOutcome;
|
||||
import org.hl7.fhir.r4.utils.FHIRPathEngine;
|
||||
import org.hl7.fhir.r4.utils.FHIRPathEngine.IEvaluationContext;
|
||||
import org.hl7.fhir.r4.utils.IResourceValidator;
|
||||
import org.hl7.fhir.r4.utils.NarrativeGenerator;
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
import org.hl7.fhir.utilities.xml.XMLUtil;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class SnapShotGenerationTests {
|
||||
|
||||
public enum TestFetchMode {
|
||||
INPUT,
|
||||
OUTPUT,
|
||||
INCLUDE
|
||||
}
|
||||
|
||||
public static class Rule {
|
||||
private String description;
|
||||
private String expression;
|
||||
public Rule(String description, String expression) {
|
||||
super();
|
||||
this.description = description;
|
||||
this.expression = expression;
|
||||
}
|
||||
public Rule(Element rule) {
|
||||
super();
|
||||
this.description = rule.getAttribute("text");
|
||||
this.expression = rule.getAttribute("fhirpath");
|
||||
}
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
public String getExpression() {
|
||||
return expression;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class TestDetails {
|
||||
private String id;
|
||||
private String include;
|
||||
private String register;
|
||||
private boolean gen;
|
||||
private boolean sort;
|
||||
private boolean fail;
|
||||
private List<Rule> rules = new ArrayList<>();
|
||||
private StructureDefinition source;
|
||||
private StructureDefinition included;
|
||||
private StructureDefinition expected;
|
||||
private StructureDefinition output;
|
||||
|
||||
public TestDetails(Element test) {
|
||||
super();
|
||||
gen = "true".equals(test.getAttribute("gen"));
|
||||
sort = "true".equals(test.getAttribute("sort"));
|
||||
fail = "true".equals(test.getAttribute("fail"));
|
||||
id = test.getAttribute("id");
|
||||
include = test.getAttribute("include");
|
||||
register = test.getAttribute("register");
|
||||
Element rule = XMLUtil.getFirstChild(test);
|
||||
while (rule != null && rule.getNodeName().equals("rule")) {
|
||||
rules.add(new Rule(rule));
|
||||
rule = XMLUtil.getNextSibling(rule);
|
||||
}
|
||||
}
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
public boolean isSort() {
|
||||
return sort;
|
||||
}
|
||||
public boolean isGen() {
|
||||
return gen;
|
||||
}
|
||||
public String getInclude() {
|
||||
return include;
|
||||
}
|
||||
public boolean isFail() {
|
||||
return fail;
|
||||
}
|
||||
public StructureDefinition getIncluded() {
|
||||
return included;
|
||||
}
|
||||
public List<Rule> getRules() {
|
||||
return rules;
|
||||
}
|
||||
public StructureDefinition getSource() {
|
||||
return source;
|
||||
}
|
||||
public void setSource(StructureDefinition source) {
|
||||
this.source = source;
|
||||
}
|
||||
public StructureDefinition getExpected() {
|
||||
return expected;
|
||||
}
|
||||
public void setExpected(StructureDefinition expected) {
|
||||
this.expected = expected;
|
||||
}
|
||||
public StructureDefinition getOutput() {
|
||||
return output;
|
||||
}
|
||||
public void setOutput(StructureDefinition output) {
|
||||
this.output = output;
|
||||
}
|
||||
public void load() throws FHIRFormatError, FileNotFoundException, IOException {
|
||||
if (new File(TestingUtilities.resourceNameToFile("snapshot-generation", id+"-input.json")).exists())
|
||||
source = (StructureDefinition) new JsonParser().parse(new FileInputStream(TestingUtilities.resourceNameToFile("snapshot-generation", id+"-input.json")));
|
||||
else
|
||||
source = (StructureDefinition) new XmlParser().parse(new FileInputStream(TestingUtilities.resourceNameToFile("snapshot-generation", id+"-input.xml")));
|
||||
if (!fail)
|
||||
expected = (StructureDefinition) new XmlParser().parse(new FileInputStream(TestingUtilities.resourceNameToFile("snapshot-generation", id+"-expected.xml")));
|
||||
if (!Utilities.noString(include))
|
||||
included = (StructureDefinition) new XmlParser().parse(new FileInputStream(TestingUtilities.resourceNameToFile("snapshot-generation", include+".xml")));
|
||||
if (!Utilities.noString(register)) {
|
||||
included = (StructureDefinition) new XmlParser().parse(new FileInputStream(TestingUtilities.resourceNameToFile("snapshot-generation", register+".xml")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class TestPKP implements ProfileKnowledgeProvider {
|
||||
|
||||
@Override
|
||||
|
@ -68,13 +187,13 @@ public class SnapShotGenerationTests {
|
|||
|
||||
@Override
|
||||
public boolean isResource(String typeSimple) {
|
||||
StructureDefinition sd = TestingUtilities.context().fetchTypeDefinition(name);
|
||||
StructureDefinition sd = TestingUtilities.context().fetchTypeDefinition(typeSimple);
|
||||
return (sd != null) && (sd.getDerivation() == TypeDerivationRule.SPECIALIZATION) && (sd.getKind() == StructureDefinitionKind.RESOURCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasLinkFor(String typeSimple) {
|
||||
return isDatatype(name);
|
||||
return isDatatype(typeSimple);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -90,6 +209,14 @@ public class SnapShotGenerationTests {
|
|||
return br;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BindingResolution resolveBinding(StructureDefinition def, String url, String path) throws FHIRException {
|
||||
BindingResolution br = new BindingResolution();
|
||||
br.url = path+"/something.html";
|
||||
br.display = "something";
|
||||
return br;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLinkForProfile(StructureDefinition profile, String url) {
|
||||
StructureDefinition sd = TestingUtilities.context().fetchResource(StructureDefinition.class, url);
|
||||
|
@ -105,7 +232,7 @@ public class SnapShotGenerationTests {
|
|||
}
|
||||
|
||||
@Override
|
||||
public BindingResolution resolveBinding(StructureDefinition def, String url, String path) throws FHIRException {
|
||||
public String getLinkForUrl(String corePath, String s) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
@ -113,99 +240,42 @@ public class SnapShotGenerationTests {
|
|||
}
|
||||
|
||||
private static class SnapShotGenerationTestsContext implements IEvaluationContext {
|
||||
private Map<String, Resource> fixtures;
|
||||
private Map<String, StructureDefinition> snapshots = new HashMap<String, StructureDefinition>();
|
||||
public TestScript tests;
|
||||
|
||||
public void checkTestsDetails() {
|
||||
if (!"http://hl7.org/fhir/tests/snapshotgeneration".equals(tests.getUrl()))
|
||||
throw new Error("Wrong URL on test script");
|
||||
if (!tests.getSetup().isEmpty())
|
||||
throw new Error("Setup is not supported");
|
||||
if (!tests.getTeardown().isEmpty())
|
||||
throw new Error("Teardown is not supported");
|
||||
Set<String> ids = new HashSet<String>();
|
||||
Set<String> urls = new HashSet<String>();
|
||||
for (Resource r : tests.getContained()) {
|
||||
if (ids.contains(r.getId()))
|
||||
throw new Error("Unsupported: duplicate contained resource on fixture id "+r.getId());
|
||||
ids.add(r.getId());
|
||||
if (r instanceof MetadataResource) {
|
||||
MetadataResource md = (MetadataResource) r;
|
||||
if (urls.contains(md.getUrl()))
|
||||
throw new Error("Unsupported: duplicate canonical url "+md.getUrl()+" on fixture id "+r.getId());
|
||||
urls.add(md.getUrl());
|
||||
}
|
||||
}
|
||||
for (TestScriptFixtureComponent r : tests.getFixture()) {
|
||||
if (ids.contains(r.getId()))
|
||||
throw new Error("Unsupported: duplicate contained resource or fixture id "+r.getId());
|
||||
ids.add(r.getId());
|
||||
}
|
||||
Set<String> names = new HashSet<String>();
|
||||
for (TestScriptTestComponent test : tests.getTest()) {
|
||||
if (names.contains(test.getName()))
|
||||
throw new Error("Unsupported: duplicate name "+test.getName());
|
||||
names.add(test.getName());
|
||||
if (test.getAction().size() < 2)
|
||||
throw new Error("Unsupported: multiple actions required");
|
||||
if (!test.getActionFirstRep().hasOperation())
|
||||
throw new Error("Unsupported: first action must be an operation");
|
||||
for (int i = 0; i < test.getAction().size(); i++) {
|
||||
// if (!test.getAction().get(i).hasAssert())
|
||||
// throw new Error("Unsupported: following actions must be an asserts");
|
||||
TestActionComponent action = test.getAction().get(i);
|
||||
if (action.hasOperation()) {
|
||||
SetupActionOperationComponent op = test.getActionFirstRep().getOperation();
|
||||
if (!CodingUtilities.matches(op.getType(), "http://hl7.org/fhir/testscript-operation-codes", "snapshot")
|
||||
&& !CodingUtilities.matches(op.getType(), "http://hl7.org/fhir/testscript-operation-codes", "sortDifferential"))
|
||||
throw new Error("Unsupported action operation type "+CodingUtilities.present(op.getType()));
|
||||
if (!"StructureDefinition".equals(op.getResource()))
|
||||
throw new Error("Unsupported action operation resource "+op.getResource());
|
||||
if (!op.hasResponseId())
|
||||
throw new Error("Unsupported action operation: no response id");
|
||||
if (!op.hasSourceId())
|
||||
throw new Error("Unsupported action operation: no source id");
|
||||
if (!hasSource(op.getSourceId()))
|
||||
throw new Error("Unsupported action operation: source id could not be resolved");
|
||||
} else if (action.hasAssert()) {
|
||||
SetupActionAssertComponent a = action.getAssert();
|
||||
if (!a.hasLabel())
|
||||
throw new Error("Unsupported: actions must have a label");
|
||||
if (!a.hasDescription())
|
||||
throw new Error("Unsupported: actions must have a description");
|
||||
if (!a.hasExpression() && !a.hasResponse())
|
||||
throw new Error("Unsupported: actions must have an expression or a response");
|
||||
} else {
|
||||
throw new Error("Unsupported: Unrecognized action type");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasSource(String sourceId) {
|
||||
for (TestScriptFixtureComponent ds : tests.getFixture()) {
|
||||
if (sourceId.equals(ds.getId()))
|
||||
return true;
|
||||
}
|
||||
for (Resource r : tests.getContained()) {
|
||||
if (sourceId.equals(r.getId()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public List<TestDetails> tests = new ArrayList<>();
|
||||
|
||||
public Resource fetchFixture(String id) {
|
||||
if (fixtures.containsKey(id))
|
||||
return fixtures.get(id);
|
||||
|
||||
for (TestScriptFixtureComponent ds : tests.getFixture()) {
|
||||
if (id.equals(ds.getId()))
|
||||
throw new Error("not done yet");
|
||||
TestFetchMode mode = TestFetchMode.INPUT;
|
||||
if (id.equals("patient"))
|
||||
return TestingUtilities.context().fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/Patient");
|
||||
if (id.equals("valueset"))
|
||||
return TestingUtilities.context().fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/ValueSet");
|
||||
if (id.equals("organization"))
|
||||
return TestingUtilities.context().fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/Organization");
|
||||
if (id.equals("operationoutcome"))
|
||||
return TestingUtilities.context().fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/OperationOutcome");
|
||||
if (id.equals("parameters"))
|
||||
return TestingUtilities.context().fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/Parameters");
|
||||
|
||||
if (id.contains("-")) {
|
||||
String[] p = id.split("\\-");
|
||||
id = p[0];
|
||||
if (p[1].equals("output"))
|
||||
mode = TestFetchMode.OUTPUT;
|
||||
else if (p[1].equals("include"))
|
||||
mode = TestFetchMode.INCLUDE;
|
||||
}
|
||||
for (Resource r : tests.getContained()) {
|
||||
if (id.equals(r.getId()))
|
||||
return r;
|
||||
for (TestDetails td : tests) {
|
||||
if (td.getId().equals(id))
|
||||
switch (mode) {
|
||||
case INPUT: return td.getSource();
|
||||
case OUTPUT: if (td.getOutput() == null)
|
||||
throw new FHIRException("Not generated yet");
|
||||
else
|
||||
return td.getOutput();
|
||||
case INCLUDE:
|
||||
return td.getIncluded();
|
||||
default:
|
||||
throw new FHIRException("Not done yet");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -213,12 +283,12 @@ public class SnapShotGenerationTests {
|
|||
// FHIRPath methods
|
||||
@Override
|
||||
public Base resolveConstant(Object appContext, String name, boolean beforeContext) throws PathEngineException {
|
||||
return null;
|
||||
throw new Error("Not implemented yet");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDetails resolveConstantType(Object appContext, String name) throws PathEngineException {
|
||||
return null;
|
||||
throw new Error("Not implemented yet");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -251,8 +321,9 @@ public class SnapShotGenerationTests {
|
|||
list.add(res);
|
||||
return list;
|
||||
}
|
||||
throw new Error("Could not resolve "+id);
|
||||
}
|
||||
return null;
|
||||
throw new Error("Not implemented yet");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -275,195 +346,159 @@ public class SnapShotGenerationTests {
|
|||
throw new NotImplementedException("Not done yet (IGPublisherHostServices.SnapShotGenerationTestsContext), when item is element");
|
||||
}
|
||||
|
||||
}
|
||||
public StructureDefinition getByUrl(String url) {
|
||||
if (url == null)
|
||||
return null;
|
||||
for (TestDetails t : tests) {
|
||||
if (t.expected != null && url.equals(t.expected.getUrl()))
|
||||
return t.expected;
|
||||
if (t.included != null && url.equals(t.included.getUrl()))
|
||||
return t.included;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet resolveValueSet(Object appContext, String url) {
|
||||
throw new Error("Not implemented yet");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static FHIRPathEngine fp;
|
||||
|
||||
@Parameters(name = "{index}: file {0}")
|
||||
public static Iterable<Object[]> data() throws ParserConfigurationException, IOException, FHIRFormatError {
|
||||
public static Iterable<Object[]> data() throws ParserConfigurationException, IOException, FHIRFormatError, SAXException {
|
||||
|
||||
SnapShotGenerationTestsContext context = new SnapShotGenerationTestsContext();
|
||||
System.out.println("Snapshot tests using "+TestingUtilities.resourceNameToFile("snapshot-generation-tests.xml"));
|
||||
context.tests = (TestScript) new XmlParser().parse(new FileInputStream(TestingUtilities.resourceNameToFile("snapshot-generation-tests.xml")));
|
||||
|
||||
context.checkTestsDetails();
|
||||
|
||||
List<Object[]> objects = new ArrayList<Object[]>(context.tests.getTest().size());
|
||||
|
||||
for (TestScriptTestComponent e : context.tests.getTest()) {
|
||||
objects.add(new Object[] { e.getName(), e, context });
|
||||
Document tests = XMLUtil.parseFileToDom(TestingUtilities.resourceNameToFile("snapshot-generation", "manifest.xml"));
|
||||
Element test = XMLUtil.getFirstChild(tests.getDocumentElement());
|
||||
List<Object[]> objects = new ArrayList<Object[]>();
|
||||
while (test != null && test.getNodeName().equals("test")) {
|
||||
TestDetails t = new TestDetails(test);
|
||||
context.tests.add(t);
|
||||
t.load();
|
||||
objects.add(new Object[] {t.getId(), t, context });
|
||||
test = XMLUtil.getNextSibling(test);
|
||||
}
|
||||
return objects;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private final TestScriptTestComponent test;
|
||||
private final String name;
|
||||
private final TestDetails test;
|
||||
private SnapShotGenerationTestsContext context;
|
||||
private List<ValidationMessage> messages;
|
||||
|
||||
public SnapShotGenerationTests(String name, TestScriptTestComponent e, SnapShotGenerationTestsContext context) {
|
||||
this.name = name;
|
||||
this.test = e;
|
||||
public SnapShotGenerationTests(String id, TestDetails test, SnapShotGenerationTestsContext context) {
|
||||
this.test = test;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test
|
||||
public void test() throws FHIRException {
|
||||
try {
|
||||
for (Resource cr : context.tests.getContained()) {
|
||||
if (cr instanceof StructureDefinition) {
|
||||
StructureDefinition sd = (StructureDefinition) cr;
|
||||
if (sd.getType().equals("Extension")) {
|
||||
if (TestingUtilities.context().fetchResource(StructureDefinition.class, sd.getUrl()) == null) {
|
||||
sd.setUserData("path", "test-"+sd.getId()+".html");
|
||||
StructureDefinition extd = TestingUtilities.context().fetchResource(StructureDefinition.class, sd.getBaseDefinition());
|
||||
new ProfileUtilities(TestingUtilities.context(), null, null).generateSnapshot(extd, sd, sd.getUrl(), "http://hl7.org/fhir/R4", sd.getName());
|
||||
TestingUtilities.context().cacheResource(sd);
|
||||
debugSaveResource(sd);
|
||||
}
|
||||
}
|
||||
}
|
||||
public void test() throws Exception {
|
||||
if (fp == null)
|
||||
fp = new FHIRPathEngine(TestingUtilities.context());
|
||||
fp.setHostServices(context);
|
||||
messages = new ArrayList<ValidationMessage>();
|
||||
|
||||
if (test.isFail()) {
|
||||
try {
|
||||
if (test.isGen())
|
||||
testGen();
|
||||
else
|
||||
testSort();
|
||||
Assert.assertTrue("Should have failed", false);
|
||||
} catch (Throwable e) {
|
||||
Assert.assertTrue("all ok", true);
|
||||
|
||||
}
|
||||
if (fp == null)
|
||||
fp = new FHIRPathEngine(TestingUtilities.context());
|
||||
fp.setHostServices(context);
|
||||
|
||||
resolveFixtures();
|
||||
|
||||
TestScript.AssertionResponseTypes lastOpOutcome = null;
|
||||
for (int i = 0; i < test.getAction().size(); i++) {
|
||||
TestActionComponent action = test.getAction().get(i);
|
||||
StructureDefinition sdn = new StructureDefinition();
|
||||
if (action.hasOperation()) {
|
||||
lastOpOutcome = AssertionResponseTypes.OKAY;
|
||||
try {
|
||||
SetupActionOperationComponent op = action.getOperation();
|
||||
Coding opType = op.getType();
|
||||
if (opType.getSystem().equals("http://hl7.org/fhir/testscript-operation-codes") && opType.getCode().equals("snapshot")) {
|
||||
StructureDefinition source = (StructureDefinition) context.fetchFixture(op.getSourceId());
|
||||
StructureDefinition base = getSD(source.getBaseDefinition());
|
||||
StructureDefinition output = source.copy();
|
||||
ProfileUtilities pu = new ProfileUtilities(TestingUtilities.context(), null, new TestPKP());
|
||||
pu.setIds(source, false);
|
||||
if ("sort=true".equals(op.getParams())) {
|
||||
List<String> errors = new ArrayList<String>();
|
||||
int lastCount = output.getDifferential().getElement().size();
|
||||
pu.sortDifferential(base, output, source.getName(), errors);
|
||||
if (errors.size() > 0)
|
||||
throw new FHIRException("Sort failed: "+errors.toString());
|
||||
|
||||
}
|
||||
pu.generateSnapshot(base, output, source.getUrl(), "http://hl7.org/fhir/R4", source.getName());
|
||||
debugSaveResource(output);
|
||||
context.fixtures.put(op.getResponseId(), output);
|
||||
context.snapshots.put(output.getUrl(), output);
|
||||
|
||||
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(System.getProperty("java.io.tmpdir"), op.getResponseId()+".xml")), output);
|
||||
if (output.getDifferential().hasElement())
|
||||
new NarrativeGenerator("", "http://hl7.org/fhir", TestingUtilities.context()).setPkp(new TestPKP()).generate(output, null);
|
||||
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(System.getProperty("java.io.tmpdir"), op.getResponseId()+"-d.xml")), output);
|
||||
} else if (opType.getSystem().equals("http://hl7.org/fhir/testscript-operation-codes") && opType.getCode().equals("sortDifferential")) {
|
||||
StructureDefinition source = (StructureDefinition) context.fetchFixture(op.getSourceId());
|
||||
StructureDefinition base = getSD(source.getBaseDefinition());
|
||||
StructureDefinition output = source.copy();
|
||||
ProfileUtilities pu = new ProfileUtilities(TestingUtilities.context(), null, null);
|
||||
pu.setIds(source, false);
|
||||
List<String> errors = new ArrayList<String>();
|
||||
pu.sortDifferential(base, output, output.getUrl(), errors);
|
||||
if (!errors.isEmpty())
|
||||
throw new FHIRException(errors.get(0));
|
||||
context.fixtures.put(op.getResponseId(), output);
|
||||
context.snapshots.put(output.getUrl(), output);
|
||||
|
||||
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(System.getProperty("java.io.tmpdir"), op.getResponseId()+".xml")), output);
|
||||
|
||||
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(System.getProperty("java.io.tmpdir"), op.getResponseId()+".xml")), output);
|
||||
} else if (action.hasAssert()) {
|
||||
SetupActionAssertComponent a = action.getAssert();
|
||||
if (a.hasResponse() && a.getResponse().equals(TestScript.AssertionResponseTypes.BAD))
|
||||
Assert.fail(action.getAssert().getLabel()+": "+action.getAssert().getDescription());
|
||||
else {
|
||||
boolean ok = fp.evaluateToBoolean(sdn, sdn, sdn, a.getExpression());
|
||||
Assert.assertTrue(a.getLabel()+": "+a.getDescription(), ok);
|
||||
}
|
||||
} else {
|
||||
throw new Error("Unsupported operation: " + opType.getSystem() + " : " + opType.getCode());
|
||||
}
|
||||
lastOpOutcome = AssertionResponseTypes.OKAY;
|
||||
} catch (Exception e) {
|
||||
for (int j = i+1;i < test.getAction().size(); i++) {
|
||||
TestActionComponent followAction = test.getAction().get(j);
|
||||
if (followAction.hasAssert() && followAction.getAssert().hasResponse() && followAction.getAssert().getResponse().equals(TestScript.AssertionResponseTypes.BAD)) {
|
||||
lastOpOutcome = AssertionResponseTypes.BAD;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (action.hasAssert()) {
|
||||
SetupActionAssertComponent a = action.getAssert();
|
||||
if (a.getResponse() != null) {
|
||||
Assert.assertTrue(a.getLabel()+" (response): "+a.getDescription(), a.getResponse() == lastOpOutcome);
|
||||
}
|
||||
if (a.hasExpression()) {
|
||||
boolean ok = fp.evaluateToBoolean(sdn, sdn, sdn, a.getExpression());
|
||||
Assert.assertTrue(a.getLabel()+": "+a.getDescription(), ok);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new FHIRException(e);
|
||||
} else if (test.isGen())
|
||||
testGen();
|
||||
else
|
||||
testSort();
|
||||
for (Rule r : test.getRules()) {
|
||||
StructureDefinition sdn = new StructureDefinition();
|
||||
boolean ok = fp.evaluateToBoolean(sdn, sdn, sdn, r.expression);
|
||||
Assert.assertTrue(r.description, ok);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void debugSaveResource(Resource r) throws IOException {
|
||||
String dir = System.getProperty("java.io.tmpdir");
|
||||
if (new File("c:\\temp").exists())
|
||||
dir = "c:\\temp";
|
||||
String fn = Utilities.path(dir, r.fhirType()+"-"+r.getId()+".xml");
|
||||
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(fn), r);
|
||||
private void testSort() throws DefinitionException, FHIRException, IOException {
|
||||
StructureDefinition base = getSD(test.getSource().getBaseDefinition());
|
||||
test.setOutput(test.getSource().copy());
|
||||
ProfileUtilities pu = new ProfileUtilities(TestingUtilities.context(), null, null);
|
||||
pu.setIds(test.getSource(), false);
|
||||
List<String> errors = new ArrayList<String>();
|
||||
pu.sortDifferential(base, test.getOutput(), test.getOutput().getUrl(), errors);
|
||||
if (!errors.isEmpty())
|
||||
throw new FHIRException(errors.get(0));
|
||||
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(TestingUtilities.resourceNameToFile("snapshot-generation", test.getId()+"-actual.xml")), test.getOutput());
|
||||
Assert.assertTrue("Output does not match expected", test.expected.equalsDeep(test.output));
|
||||
}
|
||||
|
||||
private void testGen() throws Exception {
|
||||
if (!Utilities.noString(test.register)) {
|
||||
ProfileUtilities pu = new ProfileUtilities(TestingUtilities.context(), null, null);
|
||||
pu.setNewSlicingProcessing(true);
|
||||
List<String> errors = new ArrayList<String>();
|
||||
pu.setIds(test.included, false);
|
||||
StructureDefinition base = TestingUtilities.context().fetchResource(StructureDefinition.class, test.included.getBaseDefinition());
|
||||
pu.generateSnapshot(base, test.included, test.included.getUrl(), "http://test.org/profile", test.included.getName());
|
||||
TestingUtilities.context().cacheResource(test.included);
|
||||
}
|
||||
StructureDefinition base = getSD(test.getSource().getBaseDefinition());
|
||||
if (!base.getUrl().equals(test.getSource().getBaseDefinition()))
|
||||
throw new Exception("URL mismatch on base: "+base.getUrl()+" wanting "+test.getSource().getBaseDefinition());
|
||||
|
||||
StructureDefinition output = test.getSource().copy();
|
||||
ProfileUtilities pu = new ProfileUtilities(TestingUtilities.context(), messages , new TestPKP());
|
||||
pu.setNewSlicingProcessing(true);
|
||||
pu.setThrowException(true);
|
||||
pu.setDebug(true);
|
||||
pu.setIds(test.getSource(), false);
|
||||
if (test.isSort()) {
|
||||
List<String> errors = new ArrayList<String>();
|
||||
int lastCount = output.getDifferential().getElement().size();
|
||||
pu.sortDifferential(base, output, test.getSource().getName(), errors);
|
||||
if (errors.size() > 0)
|
||||
throw new FHIRException("Sort failed: "+errors.toString());
|
||||
}
|
||||
try {
|
||||
pu.generateSnapshot(base, output, test.getSource().getUrl(), "http://test.org/profile", test.getSource().getName());
|
||||
} catch (Throwable e) {
|
||||
System.out.println("\r\nException: "+e.getMessage());
|
||||
throw e;
|
||||
}
|
||||
if (output.getDifferential().hasElement())
|
||||
new NarrativeGenerator("", "http://hl7.org/fhir", TestingUtilities.context()).setPkp(new TestPKP()).generate(output, null);
|
||||
test.output = output;
|
||||
TestingUtilities.context().cacheResource(output);
|
||||
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(TestingUtilities.resourceNameToFile("snapshot-generation", test.getId()+"-actual.xml")), output);
|
||||
StructureDefinition t1 = test.expected.copy();
|
||||
t1.setText(null);
|
||||
StructureDefinition t2 = test.output.copy();
|
||||
t2.setText(null);
|
||||
Assert.assertTrue("Output does not match expected", t1.equalsDeep(t2));
|
||||
}
|
||||
|
||||
private StructureDefinition getSD(String url) throws DefinitionException, FHIRException, IOException {
|
||||
StructureDefinition sd = context.snapshots.get(url);
|
||||
if (sd == null)
|
||||
sd = findContainedProfile(url);
|
||||
StructureDefinition sd = context.getByUrl(url);
|
||||
if (sd == null)
|
||||
sd = TestingUtilities.context().fetchResource(StructureDefinition.class, url);
|
||||
if (!sd.hasSnapshot()) {
|
||||
StructureDefinition base = getSD(sd.getBaseDefinition());
|
||||
ProfileUtilities pu = new ProfileUtilities(TestingUtilities.context(), messages , new TestPKP());
|
||||
pu.setNewSlicingProcessing(true);
|
||||
List<String> errors = new ArrayList<String>();
|
||||
pu.sortDifferential(base, sd, url, errors);
|
||||
if (!errors.isEmpty())
|
||||
throw new FHIRException(errors.get(0));
|
||||
pu.setIds(sd, false);
|
||||
pu.generateSnapshot(base, sd, sd.getUrl(), "http://test.org/profile", sd.getName());
|
||||
}
|
||||
return sd;
|
||||
}
|
||||
|
||||
private StructureDefinition findContainedProfile(String url) throws DefinitionException, FHIRException, IOException {
|
||||
for (Resource r : context.tests.getContained()) {
|
||||
if (r instanceof StructureDefinition) {
|
||||
StructureDefinition sd = (StructureDefinition) r;
|
||||
if (sd.getUrl().equals(url)) {
|
||||
StructureDefinition p = sd.copy();
|
||||
ProfileUtilities pu = new ProfileUtilities(TestingUtilities.context(), null, null);
|
||||
pu.setIds(p, false);
|
||||
List<String> errors = new ArrayList<String>();
|
||||
pu.sortDifferential(getSD(p.getBaseDefinition()), p, url, errors);
|
||||
if (!errors.isEmpty())
|
||||
throw new FHIRException(errors.get(0));
|
||||
pu.generateSnapshot(getSD(p.getBaseDefinition()), p, p.getUrl(), "http://hl7.org/fhir/R4", p.getName());
|
||||
debugSaveResource(p);
|
||||
return p;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void resolveFixtures() {
|
||||
if (context.fixtures == null) {
|
||||
context.fixtures = new HashMap<String, Resource>();
|
||||
for (TestScriptFixtureComponent fd : context.tests.getFixture()) {
|
||||
Resource r = TestingUtilities.context().fetchResource(Resource.class, fd.getResource().getReference());
|
||||
context.fixtures.put(fd.getId(), r);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -526,7 +526,8 @@ public abstract class BaseWorkerContext implements IWorkerContext {
|
|||
pIn.addParameter().setName("coding").setValue(code);
|
||||
if (implySystem)
|
||||
pIn.addParameter().setName("implySystem").setValue(new BooleanType(true));
|
||||
setTerminologyOptions(options, pIn);
|
||||
if (options != null)
|
||||
setTerminologyOptions(options, pIn);
|
||||
res = validateOnServer(vs, pIn);
|
||||
} catch (Exception e) {
|
||||
res = new ValidationResult(IssueSeverity.ERROR, e.getMessage() == null ? e.getClass().getName() : e.getMessage()).setTxLink(txLog == null ? null : txLog.getLastId());
|
||||
|
@ -566,7 +567,8 @@ public abstract class BaseWorkerContext implements IWorkerContext {
|
|||
try {
|
||||
Parameters pIn = new Parameters();
|
||||
pIn.addParameter().setName("codeableConcept").setValue(code);
|
||||
setTerminologyOptions(options, pIn);
|
||||
if (options != null)
|
||||
setTerminologyOptions(options, pIn);
|
||||
res = validateOnServer(vs, pIn);
|
||||
} catch (Exception e) {
|
||||
res = new ValidationResult(IssueSeverity.ERROR, e.getMessage() == null ? e.getClass().getName() : e.getMessage()).setTxLink(txLog.getLastId());
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package org.hl7.fhir.r5.formats;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* org.hl7.fhir.r5
|
||||
|
@ -56,6 +59,8 @@ import java.net.URI;
|
|||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat;
|
||||
import org.hl7.fhir.r5.model.Resource;
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
|
||||
public abstract class FormatUtilities {
|
||||
public static final String ID_REGEX = "[A-Za-z0-9\\-\\.]{1,64}";
|
||||
|
@ -146,5 +151,12 @@ public abstract class FormatUtilities {
|
|||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
public static Resource loadFile(String path) throws FileNotFoundException, IOException, FHIRException {
|
||||
byte[] src = TextFile.fileToBytes(path);
|
||||
FhirFormat fmt = determineFormat(src);
|
||||
ParserBase parser = makeParser(fmt);
|
||||
return parser.parse(src);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -295,9 +295,19 @@ public abstract class XmlParserBase extends ParserBase implements IParser {
|
|||
}
|
||||
|
||||
|
||||
protected void unknownContent(XmlPullParser xpp) throws FHIRFormatError {
|
||||
protected void unknownContent(XmlPullParser xpp) throws FHIRFormatError, XmlPullParserException, IOException {
|
||||
if (!isAllowUnknownContent())
|
||||
throw new FHIRFormatError("Unknown Content "+xpp.getName()+" @ "+pathForLocation(xpp));
|
||||
// otherwise, read over whatever element this is
|
||||
int count = 1;
|
||||
do {
|
||||
xpp.next();
|
||||
if (xpp.getEventType() == XmlPullParser.END_TAG)
|
||||
count--;
|
||||
if (xpp.getEventType() == XmlPullParser.START_TAG)
|
||||
count++;
|
||||
} while (count > 0);
|
||||
xpp.next();
|
||||
}
|
||||
|
||||
protected XhtmlNode parseXhtml(XmlPullParser xpp) throws XmlPullParserException, IOException, FHIRFormatError {
|
||||
|
|
|
@ -1,240 +0,0 @@
|
|||
package org.hl7.fhir.r4.validation;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* org.hl7.fhir.validation
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 Health Level 7
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.*;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r4.elementmodel.Element;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.Questionnaire.*;
|
||||
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
|
||||
/**
|
||||
* Evaluates Questionnaire.item.enableWhen against a QuestionnaireResponse.
|
||||
* Ignores possible modifierExtensions and extensions.
|
||||
*
|
||||
*/
|
||||
public class DefaultEnableWhenEvaluator implements IEnableWhenEvaluator {
|
||||
public static final String LINKID_ELEMENT = "linkId";
|
||||
public static final String ITEM_ELEMENT = "item";
|
||||
public static final String ANSWER_ELEMENT = "answer";
|
||||
|
||||
@Override
|
||||
public boolean isQuestionEnabled(QuestionnaireItemComponent questionnaireItem, Element questionnaireResponse) {
|
||||
if (!questionnaireItem.hasEnableWhen()) {
|
||||
return true;
|
||||
}
|
||||
List<EnableWhenResult> evaluationResults = questionnaireItem.getEnableWhen()
|
||||
.stream()
|
||||
.map(enableCondition -> evaluateCondition(enableCondition, questionnaireResponse,
|
||||
questionnaireItem.getLinkId()))
|
||||
.collect(Collectors.toList());
|
||||
return checkConditionResults(evaluationResults, questionnaireItem);
|
||||
}
|
||||
|
||||
|
||||
public boolean checkConditionResults(List<EnableWhenResult> evaluationResults,
|
||||
QuestionnaireItemComponent questionnaireItem) {
|
||||
if (questionnaireItem.hasEnableBehavior() && questionnaireItem.getEnableBehavior() == EnableWhenBehavior.ANY){
|
||||
return evaluationResults.stream().anyMatch(EnableWhenResult::isEnabled);
|
||||
} if (questionnaireItem.hasEnableBehavior() && questionnaireItem.getEnableBehavior() == EnableWhenBehavior.ALL){
|
||||
return evaluationResults.stream().allMatch(EnableWhenResult::isEnabled);
|
||||
}
|
||||
//TODO: Throw exception? enableBehavior is mandatory when there are multiple conditions
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
protected EnableWhenResult evaluateCondition(QuestionnaireItemEnableWhenComponent enableCondition,
|
||||
Element questionnaireResponse, String linkId) {
|
||||
//TODO: Fix EnableWhenResult stuff
|
||||
List<Element> answerItems = findQuestionAnswers(questionnaireResponse,
|
||||
enableCondition.getQuestion());
|
||||
QuestionnaireItemOperator operator = enableCondition.getOperator();
|
||||
if (operator == QuestionnaireItemOperator.EXISTS){
|
||||
Type answer = enableCondition.getAnswer();
|
||||
if (!(answer instanceof BooleanType)){
|
||||
throw new UnprocessableEntityException("Exists-operator requires answerBoolean");
|
||||
}
|
||||
return new EnableWhenResult(((BooleanType)answer).booleanValue() != answerItems.isEmpty(),
|
||||
linkId, enableCondition, questionnaireResponse);
|
||||
}
|
||||
boolean result = answerItems
|
||||
.stream()
|
||||
.anyMatch(answer -> evaluateAnswer(answer, enableCondition.getAnswer(), enableCondition.getOperator()));
|
||||
return new EnableWhenResult(result, linkId, enableCondition, questionnaireResponse);
|
||||
}
|
||||
|
||||
private Type convertToType(Element element) throws FHIRException {
|
||||
if (element.fhirType().equals("BackboneElement")) {
|
||||
return null;
|
||||
}
|
||||
Type b = new Factory().create(element.fhirType());
|
||||
if (b instanceof PrimitiveType) {
|
||||
((PrimitiveType<?>) b).setValueAsString(element.primitiveValue());
|
||||
} else {
|
||||
for (Element child : element.getChildren()) {
|
||||
if (!isExtension(child)) {
|
||||
b.setProperty(child.getName(), convertToType(child));
|
||||
}
|
||||
}
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
private boolean isExtension(Element element) {
|
||||
return "Extension".equals(element.fhirType());
|
||||
}
|
||||
|
||||
protected boolean evaluateAnswer(Element answer, Type expectedAnswer, QuestionnaireItemOperator questionnaireItemOperator) {
|
||||
Type actualAnswer;
|
||||
if (isExtension(answer)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
actualAnswer = convertToType(answer);
|
||||
if (actualAnswer == null) {
|
||||
return false;
|
||||
}
|
||||
} catch (FHIRException e) {
|
||||
throw new UnprocessableEntityException("Unexpected answer type", e);
|
||||
}
|
||||
if (!actualAnswer.getClass().equals(expectedAnswer.getClass())) {
|
||||
throw new UnprocessableEntityException("Expected answer and actual answer have incompatible types");
|
||||
}
|
||||
if (expectedAnswer instanceof Coding) {
|
||||
return compareCodingAnswer((Coding)expectedAnswer, (Coding)actualAnswer, questionnaireItemOperator);
|
||||
} else if ((expectedAnswer instanceof PrimitiveType)) {
|
||||
return comparePrimitiveAnswer((PrimitiveType<?>)actualAnswer, (PrimitiveType<?>)expectedAnswer, questionnaireItemOperator);
|
||||
} else if (expectedAnswer instanceof Quantity) {
|
||||
return compareQuantityAnswer((Quantity)actualAnswer, (Quantity)expectedAnswer, questionnaireItemOperator);
|
||||
}
|
||||
// TODO: Attachment, reference?
|
||||
throw new UnprocessableEntityException("Unimplemented answer type: " + expectedAnswer.getClass());
|
||||
}
|
||||
|
||||
|
||||
private boolean compareQuantityAnswer(Quantity actualAnswer, Quantity expectedAnswer, QuestionnaireItemOperator questionnaireItemOperator) {
|
||||
return compareComparable(actualAnswer.getValue(), expectedAnswer.getValue(), questionnaireItemOperator);
|
||||
}
|
||||
|
||||
|
||||
private boolean comparePrimitiveAnswer(PrimitiveType<?> actualAnswer, PrimitiveType<?> expectedAnswer, QuestionnaireItemOperator questionnaireItemOperator) {
|
||||
if (actualAnswer.getValue() instanceof Comparable){
|
||||
return compareComparable((Comparable<?>)actualAnswer.getValue(), (Comparable<?>) expectedAnswer.getValue(), questionnaireItemOperator);
|
||||
} else if (questionnaireItemOperator == QuestionnaireItemOperator.EQUAL){
|
||||
return actualAnswer.equalsShallow(expectedAnswer);
|
||||
} else if (questionnaireItemOperator == QuestionnaireItemOperator.NOT_EQUAL){
|
||||
return !actualAnswer.equalsShallow(expectedAnswer);
|
||||
}
|
||||
throw new UnprocessableEntityException("Bad operator for PrimitiveType comparison");
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private boolean compareComparable(Comparable actual, Comparable expected,
|
||||
QuestionnaireItemOperator questionnaireItemOperator) {
|
||||
int result = actual.compareTo(expected);
|
||||
|
||||
if (questionnaireItemOperator == QuestionnaireItemOperator.EQUAL){
|
||||
return result == 0;
|
||||
} else if (questionnaireItemOperator == QuestionnaireItemOperator.NOT_EQUAL){
|
||||
return result != 0;
|
||||
} else if (questionnaireItemOperator == QuestionnaireItemOperator.GREATER_OR_EQUAL){
|
||||
return result >= 0;
|
||||
} else if (questionnaireItemOperator == QuestionnaireItemOperator.LESS_OR_EQUAL){
|
||||
return result <= 0;
|
||||
} else if (questionnaireItemOperator == QuestionnaireItemOperator.LESS_THAN){
|
||||
return result < 0;
|
||||
} else if (questionnaireItemOperator == QuestionnaireItemOperator.GREATER_THAN){
|
||||
return result > 0;
|
||||
}
|
||||
|
||||
throw new UnprocessableEntityException("Bad operator for PrimitiveType comparison");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively look for answers to questions with the given link id
|
||||
*/
|
||||
private List<Element> findQuestionAnswers(Element questionnaireResponse, String question) {
|
||||
List<Element> retVal = new ArrayList<>();
|
||||
|
||||
List<Element> items = questionnaireResponse.getChildren(ITEM_ELEMENT);
|
||||
for (Element next : items) {
|
||||
if (hasLinkId(next, question)) {
|
||||
List<Element> answers = extractAnswer(next);
|
||||
retVal.addAll(answers);
|
||||
}
|
||||
retVal.addAll(findQuestionAnswers(next, question));
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private List<Element> extractAnswer(Element item) {
|
||||
return item.getChildrenByName(ANSWER_ELEMENT)
|
||||
.stream()
|
||||
.flatMap(c -> c.getChildren().stream())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private boolean compareCodingAnswer(Coding expectedAnswer, Coding actualAnswer, QuestionnaireItemOperator questionnaireItemOperator) {
|
||||
boolean result = compareSystems(expectedAnswer, actualAnswer) && compareCodes(expectedAnswer, actualAnswer);
|
||||
if (questionnaireItemOperator == QuestionnaireItemOperator.EQUAL){
|
||||
return result == true;
|
||||
} else if (questionnaireItemOperator == QuestionnaireItemOperator.NOT_EQUAL){
|
||||
return result == false;
|
||||
}
|
||||
throw new UnprocessableEntityException("Bad operator for Coding comparison");
|
||||
}
|
||||
|
||||
private boolean compareCodes(Coding expectedCoding, Coding value) {
|
||||
if (expectedCoding.hasCode() != value.hasCode()) {
|
||||
return false;
|
||||
}
|
||||
if (expectedCoding.hasCode()) {
|
||||
return expectedCoding.getCode().equals(value.getCode());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean compareSystems(Coding expectedCoding, Coding value) {
|
||||
if (expectedCoding.hasSystem() && !value.hasSystem()) {
|
||||
return false;
|
||||
}
|
||||
if (expectedCoding.hasSystem()) {
|
||||
return expectedCoding.getSystem().equals(value.getSystem());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean hasLinkId(Element item, String linkId) {
|
||||
Element linkIdChild = item.getNamedChild(LINKID_ELEMENT);
|
||||
if (linkIdChild != null && linkIdChild.getValue().equals(linkId)){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,357 @@
|
|||
package org.hl7.fhir.r4.validation;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* org.hl7.fhir.validation
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 Health Level 7
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.*;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r4.elementmodel.Element;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.Questionnaire.*;
|
||||
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
|
||||
/**
|
||||
* Evaluates Questionnaire.item.enableWhen against a QuestionnaireResponse.
|
||||
* Ignores possible modifierExtensions and extensions.
|
||||
*
|
||||
*/
|
||||
public class EnableWhenEvaluator {
|
||||
public static final String LINKID_ELEMENT = "linkId";
|
||||
public static final String ITEM_ELEMENT = "item";
|
||||
public static final String ANSWER_ELEMENT = "answer";
|
||||
|
||||
|
||||
public static class QuestionnaireAnswerPair {
|
||||
private QuestionnaireItemComponent q;
|
||||
private Element a;
|
||||
|
||||
public QuestionnaireAnswerPair(QuestionnaireItemComponent q, Element a) {
|
||||
super();
|
||||
this.q = q;
|
||||
this.a = a;
|
||||
}
|
||||
public QuestionnaireItemComponent getQ() {
|
||||
return q;
|
||||
}
|
||||
public Element getA() {
|
||||
return a;
|
||||
}
|
||||
|
||||
}
|
||||
public static class QStack extends ArrayList<QuestionnaireAnswerPair> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private Questionnaire q;
|
||||
private Element a;
|
||||
|
||||
public QStack(Questionnaire q, Element a) {
|
||||
super();
|
||||
this.q = q;
|
||||
this.a = a;
|
||||
}
|
||||
|
||||
|
||||
public Questionnaire getQ() {
|
||||
return q;
|
||||
}
|
||||
|
||||
|
||||
public Element getA() {
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
public QStack push(QuestionnaireItemComponent q, Element a) {
|
||||
QStack self = new QStack(this.q, this.a);
|
||||
self.addAll(this);
|
||||
self.add(new QuestionnaireAnswerPair(q, a));
|
||||
return self;
|
||||
}
|
||||
}
|
||||
|
||||
public static class EnableWhenResult {
|
||||
private final boolean enabled;
|
||||
private final QuestionnaireItemEnableWhenComponent enableWhenCondition;
|
||||
|
||||
/**
|
||||
* Evaluation result of enableWhen condition
|
||||
*
|
||||
* @param enabled
|
||||
* Evaluation result
|
||||
* @param linkId
|
||||
* LinkId of the questionnaire item
|
||||
* @param enableWhenCondition
|
||||
* Evaluated enableWhen condition
|
||||
* @param responseItem
|
||||
* item in QuestionnaireResponse
|
||||
*/
|
||||
public EnableWhenResult(boolean enabled, QuestionnaireItemEnableWhenComponent enableWhenCondition) {
|
||||
this.enabled = enabled;
|
||||
this.enableWhenCondition = enableWhenCondition;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public QuestionnaireItemEnableWhenComponent getEnableWhenCondition() {
|
||||
return enableWhenCondition;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* the stack contains a set of QR items that represent the tree of the QR being validated, each tagged with the definition of the item from the Q for the QR being validated
|
||||
*
|
||||
* the itembeing validated is in the context of the stack. For root items, the stack is empty.
|
||||
*
|
||||
* The context Questionnaire and QuestionnaireResponse are always available
|
||||
*
|
||||
* @param questionnaireItem
|
||||
* @param questionnaireResponse
|
||||
* @param qstack
|
||||
* @return
|
||||
*/
|
||||
public boolean isQuestionEnabled(QuestionnaireItemComponent qitem, QStack qstack) {
|
||||
if (!qitem.hasEnableWhen()) {
|
||||
return true;
|
||||
}
|
||||
List<EnableWhenResult> evaluationResults = qitem.getEnableWhen()
|
||||
.stream()
|
||||
.map(enableCondition -> evaluateCondition(enableCondition, qitem, qstack))
|
||||
.collect(Collectors.toList());
|
||||
return checkConditionResults(evaluationResults, qitem);
|
||||
}
|
||||
|
||||
|
||||
public boolean checkConditionResults(List<EnableWhenResult> evaluationResults, QuestionnaireItemComponent questionnaireItem) {
|
||||
if ((questionnaireItem.hasEnableBehavior() && questionnaireItem.getEnableBehavior() == EnableWhenBehavior.ANY) || evaluationResults.size() == 1){
|
||||
return evaluationResults.stream().anyMatch(EnableWhenResult::isEnabled);
|
||||
} if (questionnaireItem.hasEnableBehavior() && questionnaireItem.getEnableBehavior() == EnableWhenBehavior.ALL){
|
||||
return evaluationResults.stream().allMatch(EnableWhenResult::isEnabled);
|
||||
}
|
||||
//TODO: Throw exception? enableBehavior is mandatory when there are multiple conditions
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
protected EnableWhenResult evaluateCondition(QuestionnaireItemEnableWhenComponent enableCondition, QuestionnaireItemComponent qitem, QStack qstack) {
|
||||
List<Element> answerItems = findQuestionAnswers(qstack, qitem, enableCondition);
|
||||
QuestionnaireItemOperator operator = enableCondition.getOperator();
|
||||
if (operator == QuestionnaireItemOperator.EXISTS){
|
||||
Type answer = enableCondition.getAnswer();
|
||||
if (!(answer instanceof BooleanType)){
|
||||
throw new UnprocessableEntityException("Exists-operator requires answerBoolean");
|
||||
}
|
||||
return new EnableWhenResult(((BooleanType)answer).booleanValue() != answerItems.isEmpty(), enableCondition);
|
||||
}
|
||||
boolean result = answerItems
|
||||
.stream()
|
||||
.anyMatch(answer -> evaluateAnswer(answer, enableCondition.getAnswer(), enableCondition.getOperator()));
|
||||
return new EnableWhenResult(result, enableCondition);
|
||||
}
|
||||
|
||||
private Type convertToType(Element element) throws FHIRException {
|
||||
if (element.fhirType().equals("BackboneElement")) {
|
||||
return null;
|
||||
}
|
||||
Type b = new Factory().create(element.fhirType());
|
||||
if (b instanceof PrimitiveType) {
|
||||
((PrimitiveType<?>) b).setValueAsString(element.primitiveValue());
|
||||
} else {
|
||||
for (Element child : element.getChildren()) {
|
||||
if (!isExtension(child)) {
|
||||
b.setProperty(child.getName(), convertToType(child));
|
||||
}
|
||||
}
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
private boolean isExtension(Element element) {
|
||||
return "Extension".equals(element.fhirType());
|
||||
}
|
||||
|
||||
protected boolean evaluateAnswer(Element answer, Type expectedAnswer, QuestionnaireItemOperator questionnaireItemOperator) {
|
||||
Type actualAnswer;
|
||||
if (isExtension(answer)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
actualAnswer = convertToType(answer);
|
||||
if (actualAnswer == null) {
|
||||
return false;
|
||||
}
|
||||
} catch (FHIRException e) {
|
||||
throw new UnprocessableEntityException("Unexpected answer type", e);
|
||||
}
|
||||
if (!actualAnswer.getClass().equals(expectedAnswer.getClass())) {
|
||||
throw new UnprocessableEntityException("Expected answer and actual answer have incompatible types");
|
||||
}
|
||||
if (expectedAnswer instanceof Coding) {
|
||||
return compareCodingAnswer((Coding)expectedAnswer, (Coding)actualAnswer, questionnaireItemOperator);
|
||||
} else if ((expectedAnswer instanceof PrimitiveType)) {
|
||||
return comparePrimitiveAnswer((PrimitiveType<?>)actualAnswer, (PrimitiveType<?>)expectedAnswer, questionnaireItemOperator);
|
||||
} else if (expectedAnswer instanceof Quantity) {
|
||||
return compareQuantityAnswer((Quantity)actualAnswer, (Quantity)expectedAnswer, questionnaireItemOperator);
|
||||
}
|
||||
// TODO: Attachment, reference?
|
||||
throw new UnprocessableEntityException("Unimplemented answer type: " + expectedAnswer.getClass());
|
||||
}
|
||||
|
||||
|
||||
private boolean compareQuantityAnswer(Quantity actualAnswer, Quantity expectedAnswer, QuestionnaireItemOperator questionnaireItemOperator) {
|
||||
return compareComparable(actualAnswer.getValue(), expectedAnswer.getValue(), questionnaireItemOperator);
|
||||
}
|
||||
|
||||
|
||||
private boolean comparePrimitiveAnswer(PrimitiveType<?> actualAnswer, PrimitiveType<?> expectedAnswer, QuestionnaireItemOperator questionnaireItemOperator) {
|
||||
if (actualAnswer.getValue() instanceof Comparable){
|
||||
return compareComparable((Comparable<?>)actualAnswer.getValue(), (Comparable<?>) expectedAnswer.getValue(), questionnaireItemOperator);
|
||||
} else if (questionnaireItemOperator == QuestionnaireItemOperator.EQUAL){
|
||||
return actualAnswer.equalsShallow(expectedAnswer);
|
||||
} else if (questionnaireItemOperator == QuestionnaireItemOperator.NOT_EQUAL){
|
||||
return !actualAnswer.equalsShallow(expectedAnswer);
|
||||
}
|
||||
throw new UnprocessableEntityException("Bad operator for PrimitiveType comparison");
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private boolean compareComparable(Comparable actual, Comparable expected,
|
||||
QuestionnaireItemOperator questionnaireItemOperator) {
|
||||
int result = actual.compareTo(expected);
|
||||
|
||||
if (questionnaireItemOperator == QuestionnaireItemOperator.EQUAL){
|
||||
return result == 0;
|
||||
} else if (questionnaireItemOperator == QuestionnaireItemOperator.NOT_EQUAL){
|
||||
return result != 0;
|
||||
} else if (questionnaireItemOperator == QuestionnaireItemOperator.GREATER_OR_EQUAL){
|
||||
return result >= 0;
|
||||
} else if (questionnaireItemOperator == QuestionnaireItemOperator.LESS_OR_EQUAL){
|
||||
return result <= 0;
|
||||
} else if (questionnaireItemOperator == QuestionnaireItemOperator.LESS_THAN){
|
||||
return result < 0;
|
||||
} else if (questionnaireItemOperator == QuestionnaireItemOperator.GREATER_THAN){
|
||||
return result > 0;
|
||||
}
|
||||
|
||||
throw new UnprocessableEntityException("Bad operator for PrimitiveType comparison: "+questionnaireItemOperator.toCode());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively look for answers to questions with the given link id, working upwards given the context
|
||||
*
|
||||
* For discussion about this, see https://chat.fhir.org/#narrow/stream/179255-questionnaire/topic/enable-when
|
||||
*
|
||||
- given sourceQ - question that contains the enableWhen reference and targetQ - question that the enableWhen references in the Q and also sourceA - answer for sourceQ and targetA - answer for targetQ in the QR
|
||||
- work up from sourceQ until you find the Q group that also contains targetQ - this is groupQ
|
||||
- work up from sourceA until you find the QR group that matches groupQ - this is groupA
|
||||
- any targetA in groupA are input for the enableWhen decision
|
||||
*/
|
||||
private List<Element> findQuestionAnswers(QStack qstack, QuestionnaireItemComponent sourceQ, QuestionnaireItemEnableWhenComponent ew) {
|
||||
QuestionnaireItemComponent targetQ = qstack.getQ().getQuestion(ew.getQuestion());
|
||||
if (targetQ != null) {
|
||||
QuestionnaireItemComponent groupQ = qstack.getQ().getCommonGroup(sourceQ, targetQ);
|
||||
if (groupQ == null) { // root is Q itself
|
||||
return findOnItem(qstack.getA(), ew.getQuestion());
|
||||
} else {
|
||||
for (int i = qstack.size() - 1; i >= 0; i--) {
|
||||
if (qstack.get(i).getQ() == groupQ) {
|
||||
// group A
|
||||
return findOnItem(qstack.get(i).getA(), ew.getQuestion());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
private List<Element> findOnItem(Element focus, String question) {
|
||||
List<Element> retVal = new ArrayList<>();
|
||||
List<Element> items = focus.getChildren(ITEM_ELEMENT);
|
||||
for (Element item : items) {
|
||||
if (hasLinkId(item, question)) {
|
||||
List<Element> answers = extractAnswer(item);
|
||||
retVal.addAll(answers);
|
||||
}
|
||||
retVal.addAll(findOnItem(item, question));
|
||||
}
|
||||
|
||||
// In case the question with the enableWhen is a direct child of the question with
|
||||
// the answer that it depends on. There is an example of this in the
|
||||
// "BO_ConsDrop" question in this test case:
|
||||
// https://github.com/jamesagnew/hapi-fhir/blob/master/hapi-fhir-validation/src/test/resources/dstu3/fmc03-questionnaire.json
|
||||
if (hasLinkId(focus, question)) {
|
||||
List<Element> answers = extractAnswer(focus);
|
||||
retVal.addAll(answers);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
private List<Element> extractAnswer(Element item) {
|
||||
return item.getChildrenByName(ANSWER_ELEMENT)
|
||||
.stream()
|
||||
.flatMap(c -> c.getChildren().stream())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private boolean compareCodingAnswer(Coding expectedAnswer, Coding actualAnswer, QuestionnaireItemOperator questionnaireItemOperator) {
|
||||
boolean result = compareSystems(expectedAnswer, actualAnswer) && compareCodes(expectedAnswer, actualAnswer);
|
||||
if (questionnaireItemOperator == QuestionnaireItemOperator.EQUAL){
|
||||
return result == true;
|
||||
} else if (questionnaireItemOperator == QuestionnaireItemOperator.NOT_EQUAL){
|
||||
return result == false;
|
||||
}
|
||||
throw new UnprocessableEntityException("Bad operator for Coding comparison");
|
||||
}
|
||||
|
||||
private boolean compareCodes(Coding expectedCoding, Coding value) {
|
||||
if (expectedCoding.hasCode() != value.hasCode()) {
|
||||
return false;
|
||||
}
|
||||
if (expectedCoding.hasCode()) {
|
||||
return expectedCoding.getCode().equals(value.getCode());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean compareSystems(Coding expectedCoding, Coding value) {
|
||||
if (expectedCoding.hasSystem() && !value.hasSystem()) {
|
||||
return false;
|
||||
}
|
||||
if (expectedCoding.hasSystem()) {
|
||||
return expectedCoding.getSystem().equals(value.getSystem());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean hasLinkId(Element item, String linkId) {
|
||||
Element linkIdChild = item.getNamedChild(LINKID_ELEMENT);
|
||||
if (linkIdChild != null && linkIdChild.getValue().equals(linkId)){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
package org.hl7.fhir.r4.validation;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* org.hl7.fhir.validation
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 Health Level 7
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import org.hl7.fhir.r4.elementmodel.Element;
|
||||
import org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemComponent;
|
||||
|
||||
public interface IEnableWhenEvaluator {
|
||||
public boolean isQuestionEnabled(QuestionnaireItemComponent questionnaireItem,
|
||||
Element questionnaireResponse);
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue