Merge pull request #904 from hapifhir/gg-202208-r5-rept

Gg 202208 r5 rept
This commit is contained in:
Grahame Grieve 2022-08-26 23:30:56 +10:00 committed by GitHub
commit 6b12f6c9da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 319 additions and 44 deletions

View File

@ -95,9 +95,11 @@ public class CodeSystemRenderer extends TerminologyRenderer {
if (cs.hasProperty()) {
boolean hasRendered = false;
boolean hasURI = false;
boolean hasDescription = false;
for (PropertyComponent p : cs.getProperty()) {
hasRendered = hasRendered || !p.getCode().equals(ToolingExtensions.getPresentation(p, p.getCodeElement()));
hasURI = hasURI || p.hasUri();
hasDescription = hasDescription || p.hasDescription();
}
x.para().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Properties", getContext().getLang()));
@ -111,7 +113,9 @@ public class CodeSystemRenderer extends TerminologyRenderer {
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "URL", getContext().getLang()));
}
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Type", getContext().getLang()));
if (hasDescription) {
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Description", getContext().getLang()));
}
for (PropertyComponent p : cs.getProperty()) {
tr = tbl.tr();
if (hasRendered) {
@ -122,21 +126,25 @@ public class CodeSystemRenderer extends TerminologyRenderer {
tr.td().tx(p.getUri());
}
tr.td().tx(p.hasType() ? p.getType().toCode() : "");
if (hasDescription) {
tr.td().tx(p.getDescription());
}
}
}
}
private boolean generateCodeSystemContent(XhtmlNode x, CodeSystem cs, boolean hasExtensions, List<UsedConceptMap> maps) throws FHIRFormatError, DefinitionException, IOException {
XhtmlNode p = x.para();
p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), "This code system "));
p.code().tx(cs.getUrl());
if (cs.getContent() == CodeSystemContentMode.COMPLETE)
p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), "This code system %s defines the following codes", cs.getUrl())+":");
p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), " defines the following codes")+":");
else if (cs.getContent() == CodeSystemContentMode.EXAMPLE)
p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), "This code system %s defines some example codes", cs.getUrl())+":");
p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), " defines some example codes")+":");
else if (cs.getContent() == CodeSystemContentMode.FRAGMENT )
p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), "This code system %s defines many codes, of which the following are a subset", cs.getUrl())+":");
p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), " defines many codes, of which the following are a subset")+":");
else if (cs.getContent() == CodeSystemContentMode.NOTPRESENT ) {
p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), "This code system %s defines many codes, but they are not represented here", cs.getUrl()));
p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), " defines many codes, but they are not represented here"));
return false;
}
XhtmlNode t = x.table( "codes");
@ -245,7 +253,7 @@ public class CodeSystemRenderer extends TerminologyRenderer {
if (cs == null) {
return false;
}
return CodeSystemUtilities.hasCode(cs, code);
return code == null ? false : CodeSystemUtilities.hasCode(cs, code);
}
return false;
}

View File

@ -313,7 +313,7 @@ public class ProfileUtilities extends TranslatingUtilities {
}
}
public static final String CONSTRAINT_STYLE = "padding-left: 3px; padding-right: 3px; border: 1px maroon solid; font-weight: bold; color: #301212; background-color: #fdeeee;";
public static final String CONSTRAINT_STYLE = "padding-left: 3px; padding-right: 3px; border: 1px maroon solid; font-weight: bold; color: #301212; background-color: #fdf4f4;";
private static final String ROW_COLOR_ERROR = "#ffcccc";
private static final String ROW_COLOR_FATAL = "#ff9999";
private static final String ROW_COLOR_WARNING = "#ffebcc";
@ -3614,6 +3614,7 @@ public class ProfileUtilities extends TranslatingUtilities {
private static final int AGG_IND = 1;
private static final int AGG_GR = 2;
private static final boolean TABLE_FORMAT_FOR_FIXED_VALUES = false;
public static final String CONSTRAINT_CHAR = "C";
private Cell genTypes(HierarchicalTableGenerator gen, Row r, ElementDefinition e, String profileBaseFileName, StructureDefinition profile, String corePath, String imagePath, boolean root, boolean mustSupportMode) {
Cell c = gen.new Cell();
@ -4365,7 +4366,7 @@ public class ProfileUtilities extends TranslatingUtilities {
checkForNoChange(element.getIsSummaryElement(), gc.addStyledText(translate("sd.table", "This element is included in summaries"), "\u03A3", null, null, null, false));
}
if (element != null && (hasNonBaseConstraints(element.getConstraint()) || hasNonBaseConditions(element.getCondition()))) {
Piece p = gc.addText("I");
Piece p = gc.addText(ProfileUtilities.CONSTRAINT_CHAR);
p.setHint(translate("sd.table", "This element has or is affected by some invariants ("+listConstraintsAndConditions(element)+")"));
p.addStyle(CONSTRAINT_STYLE);
p.setReference(context.getSpecUrl()+"conformance-rules.html#constraints");

View File

@ -95,9 +95,11 @@ public class CodeSystemRenderer extends TerminologyRenderer {
if (cs.hasProperty()) {
boolean hasRendered = false;
boolean hasURI = false;
boolean hasDescription = false;
for (PropertyComponent p : cs.getProperty()) {
hasRendered = hasRendered || !p.getCode().equals(ToolingExtensions.getPresentation(p, p.getCodeElement()));
hasURI = hasURI || p.hasUri();
hasDescription = hasDescription || p.hasDescription();
}
x.para().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Properties", getContext().getLang()));
@ -111,7 +113,9 @@ public class CodeSystemRenderer extends TerminologyRenderer {
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "URL", getContext().getLang()));
}
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Type", getContext().getLang()));
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Description", getContext().getLang()));
if (hasDescription) {
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Description", getContext().getLang()));
}
for (PropertyComponent p : cs.getProperty()) {
tr = tbl.tr();
if (hasRendered) {
@ -122,21 +126,25 @@ public class CodeSystemRenderer extends TerminologyRenderer {
tr.td().tx(p.getUri());
}
tr.td().tx(p.hasType() ? p.getType().toCode() : "");
tr.td().tx(p.getDescription());
if (hasDescription) {
tr.td().tx(p.getDescription());
}
}
}
}
private boolean generateCodeSystemContent(XhtmlNode x, CodeSystem cs, boolean hasExtensions, List<UsedConceptMap> maps) throws FHIRFormatError, DefinitionException, IOException {
XhtmlNode p = x.para();
p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), "This code system "));
p.code().tx(cs.getUrl());
if (cs.getContent() == CodeSystemContentMode.COMPLETE)
p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), "This code system %s defines the following codes", cs.getUrl())+":");
p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), " defines the following codes")+":");
else if (cs.getContent() == CodeSystemContentMode.EXAMPLE)
p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), "This code system %s defines some example codes", cs.getUrl())+":");
p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), " defines some example codes")+":");
else if (cs.getContent() == CodeSystemContentMode.FRAGMENT )
p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), "This code system %s defines many codes, of which the following are a subset", cs.getUrl())+":");
p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), " defines many codes, of which the following are a subset")+":");
else if (cs.getContent() == CodeSystemContentMode.NOTPRESENT ) {
p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), "This code system %s defines many codes, but they are not represented here", cs.getUrl()));
p.tx(getContext().getWorker().translator().translateAndFormat("xhtml-gen-cs", getContext().getLang(), " defines many codes, but they are not represented here"));
return false;
}
XhtmlNode t = x.table( "codes");

View File

@ -77,6 +77,7 @@ import org.hl7.fhir.r5.utils.EOperationOutcome;
import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.r5.utils.XVerExtensionManager;
import org.hl7.fhir.r5.utils.XVerExtensionManager.XVerExtensionStatus;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.xhtml.NodeType;
import org.hl7.fhir.utilities.xhtml.XhtmlComposer;
@ -306,6 +307,9 @@ public class ProfileDrivenRenderer extends ResourceRenderer {
return;
Base e = ew.getBase();
if (context.isShowComments()) {
x = renderCommentsSpan(x, e);
}
if (e instanceof StringType)
x.addText(((StringType) e).getValue());
@ -436,6 +440,14 @@ public class ProfileDrivenRenderer extends ResourceRenderer {
}
}
private XhtmlNode renderCommentsSpan(XhtmlNode x, Base e) {
if (e.hasFormatComment()) {
return x.span(null, CommaSeparatedStringBuilder.join("&#10;", e.getFormatCommentsPre()));
} else {
return x;
}
}
private boolean displayLeaf(ResourceWrapper res, BaseWrapper ew, ElementDefinition defn, XhtmlNode x, String name, boolean showCodeDetails) throws FHIRException, UnsupportedEncodingException, IOException {
return displayLeaf(res, ew, defn, x, name, showCodeDetails, true);
}

View File

@ -27,6 +27,7 @@ import org.hl7.fhir.utilities.xhtml.XhtmlParser;
import org.hl7.fhir.utilities.xml.XMLUtil;
import org.hl7.fhir.utilities.xml.XmlGenerator;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
public class DOMWrappers {
@ -58,7 +59,15 @@ public class DOMWrappers {
} catch (org.hl7.fhir.exceptions.FHIRException e) {
throw new FHIRException(e.getMessage(), e);
}
return context.getParser().parseType(xml, type);
Node n = element.getPreviousSibling();
Base ret = context.getParser().parseType(xml, type);
while (n != null && (n.getNodeType() == Node.COMMENT_NODE || n.getNodeType() == Node.TEXT_NODE)) {
if (n.getNodeType() == Node.COMMENT_NODE) {
ret.getFormatCommentsPre().add(0, n.getTextContent());
}
n = n.getPreviousSibling();
}
return ret;
}
@Override

View File

@ -122,6 +122,7 @@ public class RenderingContext {
private QuestionnaireRendererMode questionnaireMode = QuestionnaireRendererMode.FORM;
private boolean addGeneratedNarrativeHeader = true;
private boolean showComments = false;
private FhirPublication targetVersion;
private Locale locale;
@ -188,6 +189,7 @@ public class RenderingContext {
res.dateYearMonthFormat = dateYearMonthFormat;
res.targetVersion = targetVersion;
res.locale = locale;
res.showComments = showComments;
res.terminologyServiceOptions = terminologyServiceOptions.copy();
return res;
@ -453,8 +455,9 @@ public class RenderingContext {
return targetVersion;
}
public void setTargetVersion(FhirPublication targetVersion) {
public RenderingContext setTargetVersion(FhirPublication targetVersion) {
this.targetVersion = targetVersion;
return this;
}
public boolean isTechnicalMode() {
@ -473,8 +476,9 @@ public class RenderingContext {
}
}
public void setLocale(Locale locale) {
public RenderingContext setLocale(Locale locale) {
this.locale = locale;
return this;
}
@ -494,8 +498,9 @@ public class RenderingContext {
return timeZoneId;
}
public void setTimeZoneId(ZoneId timeZoneId) {
public RenderingContext setTimeZoneId(ZoneId timeZoneId) {
this.timeZoneId = timeZoneId;
return this;
}
@ -509,12 +514,14 @@ public class RenderingContext {
return this.dateTimeFormat;
}
public void setDateTimeFormat(DateTimeFormatter dateTimeFormat) {
public RenderingContext setDateTimeFormat(DateTimeFormatter dateTimeFormat) {
this.dateTimeFormat = dateTimeFormat;
return this;
}
public void setDateTimeFormatString(String dateTimeFormat) {
public RenderingContext setDateTimeFormatString(String dateTimeFormat) {
this.dateTimeFormat = DateTimeFormatter.ofPattern(dateTimeFormat);
return this;
}
/**
@ -527,52 +534,67 @@ public class RenderingContext {
return this.dateFormat;
}
public void setDateFormat(DateTimeFormatter dateFormat) {
public RenderingContext setDateFormat(DateTimeFormatter dateFormat) {
this.dateFormat = dateFormat;
return this;
}
public void setDateFormatString(String dateFormat) {
public RenderingContext setDateFormatString(String dateFormat) {
this.dateFormat = DateTimeFormatter.ofPattern(dateFormat);
return this;
}
public DateTimeFormatter getDateYearFormat() {
return dateYearFormat;
}
public void setDateYearFormat(DateTimeFormatter dateYearFormat) {
public RenderingContext setDateYearFormat(DateTimeFormatter dateYearFormat) {
this.dateYearFormat = dateYearFormat;
return this;
}
public void setDateYearFormatString(String dateYearFormat) {
public RenderingContext setDateYearFormatString(String dateYearFormat) {
this.dateYearFormat = DateTimeFormatter.ofPattern(dateYearFormat);
return this;
}
public DateTimeFormatter getDateYearMonthFormat() {
return dateYearMonthFormat;
}
public void setDateYearMonthFormat(DateTimeFormatter dateYearMonthFormat) {
public RenderingContext setDateYearMonthFormat(DateTimeFormatter dateYearMonthFormat) {
this.dateYearMonthFormat = dateYearMonthFormat;
return this;
}
public void setDateYearMonthFormatString(String dateYearMonthFormat) {
public RenderingContext setDateYearMonthFormatString(String dateYearMonthFormat) {
this.dateYearMonthFormat = DateTimeFormatter.ofPattern(dateYearMonthFormat);
return this;
}
public ResourceRendererMode getMode() {
return mode;
}
public void setMode(ResourceRendererMode mode) {
public RenderingContext setMode(ResourceRendererMode mode) {
this.mode = mode;
return this;
}
public boolean isContained() {
return contained;
}
public void setContained(boolean contained) {
public RenderingContext setContained(boolean contained) {
this.contained = contained;
return this;
}
public boolean isShowComments() {
return showComments;
}
public RenderingContext setShowComments(boolean showComments) {
this.showComments = showComments;
return this;
}

View File

@ -53,10 +53,13 @@ import org.hl7.fhir.r5.model.CodeType;
import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.DataType;
import org.hl7.fhir.r5.model.DateTimeType;
import org.hl7.fhir.r5.model.DecimalType;
import org.hl7.fhir.r5.model.Enumerations.PublicationStatus;
import org.hl7.fhir.r5.terminologies.CodeSystemUtilities.ConceptDefinitionComponentSorter;
import org.hl7.fhir.r5.model.Identifier;
import org.hl7.fhir.r5.model.IntegerType;
import org.hl7.fhir.r5.model.Meta;
import org.hl7.fhir.r5.model.StringType;
import org.hl7.fhir.r5.model.UriType;
import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.utilities.StandardsStatus;
@ -68,7 +71,7 @@ public class CodeSystemUtilities {
@Override
public int compare(ConceptDefinitionComponent o1, ConceptDefinitionComponent o2) {
return o1.getCode().compareTo(o2.getCode());
return o1.getCode().compareToIgnoreCase(o2.getCode());
}
}
@ -177,6 +180,58 @@ public class CodeSystemUtilities {
concept.addProperty().setCode("notSelectable").setValue(new BooleanType(true));
}
public static void setProperty(CodeSystem cs, ConceptDefinitionComponent concept, String code, DataType value) throws FHIRFormatError {
defineProperty(cs, code, propertyTypeForValue(value));
ConceptPropertyComponent p = getProperty(concept, code);
if (p != null)
p.setValue(value);
else
concept.addProperty().setCode(code).setValue(value);
}
private static PropertyType propertyTypeForValue(DataType value) {
if (value instanceof BooleanType) {
return PropertyType.BOOLEAN;
}
if (value instanceof CodeType) {
return PropertyType.CODE;
}
if (value instanceof Coding) {
return PropertyType.CODING;
}
if (value instanceof DateTimeType) {
return PropertyType.DATETIME;
}
if (value instanceof DecimalType) {
return PropertyType.DECIMAL;
}
if (value instanceof IntegerType) {
return PropertyType.INTEGER;
}
if (value instanceof StringType) {
return PropertyType.STRING;
}
throw new Error("Unknown property type "+value.getClass().getName());
}
private static void defineProperty(CodeSystem cs, String code, PropertyType pt) {
String url = "http://hl7.org/fhir/concept-properties#"+code;
for (PropertyComponent p : cs.getProperty()) {
if (p.getCode().equals(code)) {
if (!p.getUri().equals(url)) {
throw new Error("URI mismatch for code "+code+" url = "+p.getUri()+" vs "+url);
}
if (!p.getType().equals(pt)) {
throw new Error("Type mismatch for code "+code+" type = "+p.getType()+" vs "+pt);
}
return;
}
}
cs.addProperty().setCode(code).setUri(url).setType(pt).setUri(url);
}
public static void defineNotSelectableProperty(CodeSystem cs) {
defineCodeSystemProperty(cs, "notSelectable", "Indicates that the code is abstract - only intended to be used as a selector for other concepts", PropertyType.BOOLEAN);
}

View File

@ -1,5 +1,7 @@
package org.hl7.fhir.r5.terminologies;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/*
@ -47,9 +49,11 @@ import org.hl7.fhir.r5.model.UriType;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
import org.hl7.fhir.r5.model.CodeType;
import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent;
import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionPropertyComponent;
import org.hl7.fhir.r5.terminologies.CodeSystemUtilities.ConceptDefinitionComponentSorter;
import org.hl7.fhir.r5.terminologies.CodeSystemUtilities.ConceptStatus;
import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.utilities.StandardsStatus;
@ -255,4 +259,18 @@ public class ValueSetUtilities {
}
public static class ConceptReferenceComponentSorter implements Comparator<ConceptReferenceComponent> {
@Override
public int compare(ConceptReferenceComponent o1, ConceptReferenceComponent o2) {
return o1.getCode().compareToIgnoreCase(o2.getCode());
}
}
public static void sortInclude(ConceptSetComponent inc) {
Collections.sort(inc.getConcept(), new ConceptReferenceComponentSorter());
}
}

View File

@ -583,7 +583,7 @@ public class FHIRPathEngine {
fmt = fmt + " "+worker.formatMessage(I18nConstants.FHIRPATH_LOCATION, location);
}
if (holder != null) {
return new PathEngineException(fmt, holder.getStart(), holder.toString());
return new PathEngineException(fmt, holder.getStart(), holder.toString());
} else {
return new PathEngineException(fmt);
}
@ -5503,10 +5503,11 @@ public class FHIRPathEngine {
if (dt == null) {
throw makeException(expr, I18nConstants.FHIRPATH_NO_TYPE, ProfileUtilities.sdNs(t.getCode(), worker.getOverrideVersionNs()), "getChildTypesByName");
}
sdl.add(dt);
addTypeAndDescendents(sdl, dt, worker.allStructures());
// also add any descendant types
}
} else {
sdl.add(sd);
addTypeAndDescendents(sdl, sd, worker.allStructures());
if (type.contains("#")) {
tail = type.substring(type.indexOf("#")+1);
tail = tail.substring(tail.indexOf("."));
@ -5596,6 +5597,15 @@ public class FHIRPathEngine {
}
}
private void addTypeAndDescendents(List<StructureDefinition> sdl, StructureDefinition dt, List<StructureDefinition> types) {
sdl.add(dt);
for (StructureDefinition sd : types) {
if (sd.hasBaseDefinition() && sd.getBaseDefinition().equals(dt.getUrl()) && sd.getDerivation() == TypeDerivationRule.SPECIALIZATION) {
addTypeAndDescendents(sdl, sd, types);
}
}
}
private void getClassInfoChildTypesByName(String name, TypeDetails result) {
if (name.equals("namespace")) {
result.addType(TypeDetails.FP_String);

View File

@ -443,7 +443,7 @@ public class QuestionnaireBuilder {
if (u.getValue().startsWith("http://hl7.org/fhir/StructureDefinition/")) {
ValueSetExpansionContainsComponent cc = vs.getExpansion().addContains();
cc.setCode(u.getValue().substring(40));
cc.setSystem("http://hl7.org/fhir/resource-types");
cc.setSystem("http://hl7.org/fhir/fhir-types");
cc.setDisplay(cc.getCode());
}
}
@ -451,7 +451,7 @@ public class QuestionnaireBuilder {
ValueSetExpansionContainsComponent cc = vs.getExpansion().addContains();
cc.setCode(t.getWorkingCode());
cc.setDisplay(t.getWorkingCode());
cc.setSystem("http://hl7.org/fhir/data-types");
cc.setSystem("http://hl7.org/fhir/fhir-types");
} else for (UriType u : t.getProfile()) {
ProfileUtilities pu = new ProfileUtilities(context, null, null);
StructureDefinition ps = pu.getProfile(profile, u.getValue());
@ -459,7 +459,7 @@ public class QuestionnaireBuilder {
ValueSetExpansionContainsComponent cc = vs.getExpansion().addContains();
cc.setCode(u.getValue());
cc.setDisplay(ps.getType());
cc.setSystem("http://hl7.org/fhir/resource-types");
cc.setSystem("http://hl7.org/fhir/fhir-types");
}
}
}
@ -489,7 +489,7 @@ public class QuestionnaireBuilder {
Coding cc = new Coding();
a.setValue(cc);
cc.setCode(u.getValue().substring(40));
cc.setSystem("http://hl7.org/fhir/resource-types");
cc.setSystem("http://hl7.org/fhir/fhir-types");
}
}
} else {
@ -502,10 +502,10 @@ public class QuestionnaireBuilder {
if (ps != null) {
cc.setCode(t.getProfile().get(0).getValue());
cc.setSystem("http://hl7.org/fhir/resource-types");
cc.setSystem("http://hl7.org/fhir/fhir-types");
} else {
cc.setCode(t.getWorkingCode());
cc.setSystem("http://hl7.org/fhir/data-types");
cc.setSystem("http://hl7.org/fhir/fhir-types");
}
}

View File

@ -207,6 +207,9 @@ public class ToolingExtensions {
public static final String EXT_EXPAND_RULES = "http://hl7.org/fhir/StructureDefinition/valueset-expand-rules";
public static final String EXT_EXPAND_GROUP = "http://hl7.org/fhir/StructureDefinition/valueset-expand-group";
public static final String EXT_BINDING_ADDITIONAL = "http://hl7.org/fhir/tools/StructureDefinition/additional-binding";
public static final String EXT_MIN_LENGTH = "http://hl7.org/fhir/StructureDefinition/minLength";
public static final String EXT_MAX_DECIMALS = "http://hl7.org/fhir/StructureDefinition/maxDecimalPlaces";
public static final String EXT_MAX_SIZE = "http://hl7.org/fhir/StructureDefinition/maxSize";
// specific extension helpers

View File

@ -108,4 +108,12 @@ public class CommaSeparatedStringBuilder {
}
}
public static String join(String sep, List<String> list) {
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(sep);
for (String s : list) {
b.append(s);
}
return b.toString();
}
}

View File

@ -381,8 +381,10 @@ public class I18nConstants {
public static final String SD_ED_BIND_MULTIPLE_TYPES = "SD_ED_BIND_MULTIPLE_TYPES";
public static final String SD_VALUE_TYPE_IILEGAL = "SD_VALUE_TYPE_IILEGAL";
public static final String SD_VALUE_TYPE_REPEAT_HINT = "SD_VALUE_TYPE_REPEAT_HINT";
public static final String SD_VALUE_COMPLEX_FIXED = "SD_VALUE_COMPLEX_FIXED";
public static final String SD_VALUE_TYPE_REPEAT_WARNING_DOTNET = "SD_VALUE_TYPE_REPEAT_WARNING_DOTNET";
public static final String SD_NO_TYPES_OR_CONTENTREF = "SD_NO_TYPES_OR_CONTENTREF";
public static final String SD_ILLEGAL_CHARACTERISTICS = "SD_ILLEGAL_CHARACTERISTICS";
public static final String SEARCHPARAMETER_BASE_WRONG = "SEARCHPARAMETER_BASE_WRONG";
public static final String SEARCHPARAMETER_EXP_WRONG = "SEARCHPARAMETER_EXP_WRONG";
public static final String SEARCHPARAMETER_NOTFOUND = "SEARCHPARAMETER_NOTFOUND";

View File

@ -720,3 +720,5 @@ TX_SERVER_NO_BATCH_RESPONSE = The server return null from a batch validation req
BUNDLE_POSSSIBLE_MATCHES = The bundle contains no match for {1} by the rules of Bundle reference resolution, but it has multiple resources that match {0} by resource type and id
BUNDLE_BUNDLE_POSSIBLE_MATCH_NO_FU = Entry {0} matches the reference {1} by type and id but it does not match the full target URL {2} by Bundle resolution rules
BUNDLE_BUNDLE_POSSIBLE_MATCH_WRONG_FU = Entry {0} matches the reference {1} by type and id but it''s fullUrl {2} does not match the full target URL {3} by Bundle resolution rules
SD_ILLEGAL_CHARACTERISTICS = This element has a {0} but the types to do not make this kind of constraint relevant
SD_VALUE_COMPLEX_FIXED = For the complex type {0}, consider using a pattern rather than a fixed value to avoid over-constraining the instance

View File

@ -255,7 +255,7 @@ public class ValidatorCli {
System.out.println("Loading");
// Comment this out because definitions filename doesn't necessarily contain version (and many not even be 14 characters long).
// Version gets spit out a couple of lines later after we've loaded the context
String definitions = VersionUtilities.packageForVersion(cliContext.getSv()) + "#" + VersionUtilities.getCurrentVersion(cliContext.getSv());
String definitions = "dev".equals(cliContext.getSv()) ? "hl7.fhir.r5.core#current" : VersionUtilities.packageForVersion(cliContext.getSv()) + "#" + VersionUtilities.getCurrentVersion(cliContext.getSv());
ValidationEngine validator = validationService.initializeValidator(cliContext, definitions, tt);
tts.end();
switch (cliContext.getMode()) {

View File

@ -950,7 +950,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
done = true;
}
}
hint(errors, IssueType.UNKNOWN, element.line(), element.col(), path, done, I18nConstants.TERMINOLOGY_TX_SYSTEM_NOTKNOWN, system);
if (!isAllowExamples() || !Utilities.startsWithInList(system, "http://example.org", "https://example.org")) {
hint(errors, IssueType.UNKNOWN, element.line(), element.col(), path, done, I18nConstants.TERMINOLOGY_TX_SYSTEM_NOTKNOWN, system);
}
return true;
} catch (Exception e) {
return true;
@ -3205,6 +3207,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (pol == ReferenceValidationPolicy.CHECK_VALID) {
// todo....
}
// todo: if the content is a resource, check that Reference.type is describing a resource
}
private boolean isSuspiciousReference(String url) {
@ -4994,11 +4998,15 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
type = checkDefn.getType().get(0).getWorkingCode();
String stype = ei.getElement().fhirType();
if (checkDefn.isChoice() && !stype.equals(type)) {
if ("Extension".equals(profile.getType())) {
// error will be raised elsewhere
} else {
if (extensionUrl != null && !isAbsolute(extensionUrl)) {
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), ei.getPath(), false, I18nConstants.EXTENSION_PROF_TYPE, profile.getUrl(), type, stype);
} else if (!isAbstractType(type) && !"Extension".equals(profile.getType())) {
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), ei.getPath(), stype.equals(type), I18nConstants.EXTENSION_PROF_TYPE, profile.getUrl(), type, stype);
}
} else if (!isAbstractType(type)) {
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), ei.getPath(), stype.equals(type) ||
(Utilities.existsInList(type, "string", "id") && Utilities.existsInList(stype, "string", "id")), // work around a r4 problem with id/string
I18nConstants.EXTENSION_PROF_TYPE, profile.getUrl(), type, stype);
}
// Excluding reference is a kludge to get around versioning issues
@ -5231,6 +5239,11 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
}
private boolean isAbstractType(String type) {
StructureDefinition sd = context.fetchTypeDefinition(type);
return sd != null && sd.getAbstract();
}
private boolean isResourceAndTypes(ElementDefinition ed) {
if (!Utilities.existsInList(ed.getBase().getPath(), "Bundle.entry.resource", "Bundle.entry.response.outcome", "DomainResource.contained", "Parameters.parameter.resource", "Parameters.parameter.part.resource")) {
return false;

View File

@ -129,6 +129,8 @@ public class StructureDefinitionValidator extends BaseValidator {
boolean typeMustSupport = false;
List<Element> types = element.getChildrenByName("type");
Set<String> typeCodes = new HashSet<>();
Set<String> characteristics = new HashSet<>();
for (Element type : types) {
if (hasMustSupportExtension(type)) {
typeMustSupport = true;
@ -143,6 +145,12 @@ public class StructureDefinitionValidator extends BaseValidator {
}
}
typeCodes.add(tc);
Set<String> tcharacteristics = new HashSet<>();
addCharacteristics(tcharacteristics, tc);
characteristics.addAll(tcharacteristics);
if (type.hasChildren("targetProfile")) {
rule(errors, IssueType.BUSINESSRULE, stack.getLiteralPath(), tcharacteristics.contains("has-target") , I18nConstants.SD_ILLEGAL_CHARACTERISTICS, "targetProfile");
}
// check the stated profile - must be a constraint on the type
if (snapshot || sd != null) {
validateElementType(errors, type, stack.push(type, -1, null, null), sd, element.getChildValue("path"));
@ -156,6 +164,8 @@ public class StructureDefinitionValidator extends BaseValidator {
}
}
if (element.hasChild("binding")) {
rule(errors, IssueType.BUSINESSRULE, stack.getLiteralPath(), characteristics.contains("can-bind") , I18nConstants.SD_ILLEGAL_CHARACTERISTICS, "Binding");
Element binding = element.getNamedChild("binding");
validateBinding(errors, binding, stack.push(binding, -1, null, null), typeCodes, snapshot, element.getNamedChildValue("path"));
} else {
@ -163,6 +173,25 @@ public class StructureDefinitionValidator extends BaseValidator {
// String bt = boundType(typeCodes);
// hint(errors, IssueType.BUSINESSRULE, stack.getLiteralPath(), !snapshot || bt == null, I18nConstants.SD_ED_SHOULD_BIND, element.getNamedChildValue("path"), bt);
}
if (element.hasChild("maxLength")) {
rule(errors, IssueType.BUSINESSRULE, stack.getLiteralPath(), characteristics.contains("has-length") , I18nConstants.SD_ILLEGAL_CHARACTERISTICS, "MaxLength");
}
if (element.hasExtension(ToolingExtensions.EXT_MIN_LENGTH)) {
rule(errors, IssueType.BUSINESSRULE, stack.getLiteralPath(), characteristics.contains("has-length") , I18nConstants.SD_ILLEGAL_CHARACTERISTICS, "MinLength Extension");
}
if (element.hasChild("minValue")) {
rule(errors, IssueType.BUSINESSRULE, stack.getLiteralPath(), characteristics.contains("has-range") , I18nConstants.SD_ILLEGAL_CHARACTERISTICS, "MinValue");
}
if (element.hasChild("maxValue")) {
rule(errors, IssueType.BUSINESSRULE, stack.getLiteralPath(), characteristics.contains("has-range") , I18nConstants.SD_ILLEGAL_CHARACTERISTICS, "MaxValue");
}
if (element.hasExtension(ToolingExtensions.EXT_MAX_DECIMALS)) {
rule(errors, IssueType.BUSINESSRULE, stack.getLiteralPath(), characteristics.contains("is-continuous") , I18nConstants.SD_ILLEGAL_CHARACTERISTICS, "Max Decimal Places Extension");
}
if (element.hasExtension(ToolingExtensions.EXT_MAX_SIZE)) {
rule(errors, IssueType.BUSINESSRULE, stack.getLiteralPath(), characteristics.contains("has-size") , I18nConstants.SD_ILLEGAL_CHARACTERISTICS, "Max Size");
}
// in a snapshot, we validate that fixedValue, pattern, and defaultValue, if present, are all of the right type
if (snapshot && (element.getIdBase() != null) && (element.getIdBase().contains("."))) {
if (rule(errors, IssueType.EXCEPTION, stack.getLiteralPath(), !typeCodes.isEmpty() || element.hasChild("contentReference"), I18nConstants.SD_NO_TYPES_OR_CONTENTREF, element.getIdBase())) {
@ -179,7 +208,9 @@ public class StructureDefinitionValidator extends BaseValidator {
hint(errors, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), !repeating, I18nConstants.SD_VALUE_TYPE_REPEAT_HINT, element.getIdBase(), "fixed");
if (isPrimitiveType(v.fhirType())) {
warning(errors, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), !repeating, I18nConstants.SD_VALUE_TYPE_REPEAT_WARNING_DOTNET, element.getIdBase(), "fixed");
}
} else {
warning(errors, IssueType.EXCEPTION, stack.push(v, -1, null, null).getLiteralPath(), false, I18nConstants.SD_VALUE_COMPLEX_FIXED, v.fhirType());
}
}
v = element.getNamedChild("pattern");
if (v != null) {
@ -194,8 +225,81 @@ public class StructureDefinitionValidator extends BaseValidator {
}
}
private boolean addCharacteristics(Set<String> set, String tc) {
switch (tc) {
case "boolean" : return addCharacteristicsForType(set);
case "integer" : return addCharacteristicsForType(set, "has-range", "has-length");
case "integer64" : return addCharacteristicsForType(set, "has-range", "has-length");
case "decimal" :return addCharacteristicsForType(set, "has-range", "is-continuous", "has-length");
case "base64Binary" : return addCharacteristicsForType(set, "has-size");
case "instant" : return addCharacteristicsForType(set, "has-range", "is-continuous", "has-length");
case "string" : return addCharacteristicsForType(set, "has-length", "do-translations");
case "uri" : return addCharacteristicsForType(set, "has-length", "can-bind");
case "date" :return addCharacteristicsForType(set, "has-range", "has-length");
case "dateTime" : return addCharacteristicsForType(set, "has-range", "is-continuous", "has-length");
case "time" :return addCharacteristicsForType(set, "has-range", "is-continuous", "has-length");
case "canonical" :return addCharacteristicsForType(set, "has-target", "has-length");
case "code" :return addCharacteristicsForType(set, "has-length", "can-bind");
case "id" :return addCharacteristicsForType(set, "has-length");
case "markdown" :return addCharacteristicsForType(set, "do-translations");
case "oid" :return addCharacteristicsForType(set, "has-length", "can-bind");
case "positiveInt" :return addCharacteristicsForType(set, "has-range", "has-length");
case "unsignedInt" :return addCharacteristicsForType(set, "has-range", "has-length");
case "url" :return addCharacteristicsForType(set, "has-length", "can-bind");
case "uuid" :return addCharacteristicsForType(set, "has-length", "can-bind");
case "Address" :return addCharacteristicsForType(set, "do-translations");
case "Age" : return addCharacteristicsForType(set, "has-range", "is-continuous");
case "Annotation" :return addCharacteristicsForType(set);
case "Attachment" :return addCharacteristicsForType(set, "has-size", "do-translations");
case "CodeableConcept" :return addCharacteristicsForType(set, "can-bind", "do-translations");
case "CodeableReference" : return addCharacteristicsForType(set, "has-target", "can-bind", "do-translations");
case "Coding" : return addCharacteristicsForType(set, "can-bind", "do-translations");
case "ContactPoint" :return addCharacteristicsForType(set);
case "Count" :return addCharacteristicsForType(set, "has-range");
case "Distance" :return addCharacteristicsForType(set, "has-range", "is-continuous");
case "Duration" : return addCharacteristicsForType(set, "has-range", "is-continuous");
case "HumanName" :return addCharacteristicsForType(set);
case "Identifier" : return addCharacteristicsForType(set);
case "Money" : return addCharacteristicsForType(set, "has-range", "is-continuous");
case "Period" : return addCharacteristicsForType(set);
case "Quantity" :return addCharacteristicsForType(set, "has-range", "is-continuous", "can-bind", "has-units");
case "Range" :return addCharacteristicsForType(set, "has-units");
case "Ratio" :return addCharacteristicsForType(set, "has-units");
case "RatioRange" : return addCharacteristicsForType(set, "has-units");
case "Reference" : return addCharacteristicsForType(set, "has-target");
case "SampledData" :return addCharacteristicsForType(set);
case "Signature" : return addCharacteristicsForType(set);
case "Timing" : return addCharacteristicsForType(set);
case "ContactDetail" :return addCharacteristicsForType(set);
case "Contributor" :return addCharacteristicsForType(set);
case "DataRequirement" :return addCharacteristicsForType(set);
case "Expression" : return addCharacteristicsForType(set);
case "ParameterDefinition" : return addCharacteristicsForType(set);
case "RelatedArtifact" :return addCharacteristicsForType(set);
case "TriggerDefinition" :return addCharacteristicsForType(set);
case "UsageContext" :return addCharacteristicsForType(set);
case "Dosage" : return addCharacteristicsForType(set);
case "Meta" :return addCharacteristicsForType(set);
case "Resource" :return addCharacteristicsForType(set);
case "Extension" :return addCharacteristicsForType(set);
case "Narrative" :return addCharacteristicsForType(set);
case "Element" :return addCharacteristicsForType(set);
case "BackboneElement" :return addCharacteristicsForType(set);
default:
throw new Error("Unhandled data type in addCharacterstics: "+tc);
}
}
private boolean addCharacteristicsForType(Set<String> set, String... cl) {
for (String c : cl) {
set.add(c);
}
return true;
}
private boolean isPrimitiveType(String fhirType) {
StructureDefinition sd = context.fetchTypeDefinition(fhirType);
return sd != null && sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE;