2023 12 gg r6 ccda q (#1519)

* Fix for missing warnings around bundle link validation

* Fix using wrong resource type when validating constraints in data type definitions (R6)

* Fix NPE in validator processing CCDA examples

* Handle all initial value types when rendering Questionnaires

---------

Co-authored-by: Grahame Grieve <grahameg@gmail.ccom>
This commit is contained in:
Grahame Grieve 2023-12-14 04:19:32 +13:00 committed by GitHub
parent 031c5690d8
commit 1249aa4294
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 125 additions and 21 deletions

View File

@ -749,7 +749,7 @@ public class DataRenderer extends Renderer implements CodeResolver {
}
}
private void renderReference(XhtmlNode x, Reference ref) {
protected void renderReference(XhtmlNode x, Reference ref) {
if (ref.hasDisplay()) {
x.tx(ref.getDisplay());
} else if (ref.hasReference()) {
@ -1199,7 +1199,7 @@ public class DataRenderer extends Renderer implements CodeResolver {
}
}
private String displayIdentifier(Identifier ii) {
protected String displayIdentifier(Identifier ii) {
String s = Utilities.noString(ii.getValue()) ? "?ngen-9?" : ii.getValue();
NamingSystem ns = context.getContext().getNSUrlMap().get(ii.getSystem());
if (ns != null) {
@ -1528,6 +1528,11 @@ public class DataRenderer extends Renderer implements CodeResolver {
}
}
protected void renderQuantity(HierarchicalTableGenerator gen, List<Piece> pieces, Quantity q, boolean showCodeDetails) {
pieces.add(gen.new Piece(null, displayQuantity(q), null));
}
public String displayRange(Range q) {
if (!q.hasLow() && !q.hasHigh())
return "?";

View File

@ -350,8 +350,14 @@ public class QuestionnaireRenderer extends TerminologyRenderer {
defn.getPieces().add(gen.new Piece(null, " = ", null));
if (v.getValue().isPrimitive()) {
defn.getPieces().add(gen.new Piece(null, v.getValue().primitiveValue(), null));
} else {
} else if (v.hasValueCoding()) {
renderCoding(gen, defn.getPieces(), v.getValueCoding());
} else if (v.hasValueQuantity()) {
renderQuantity(gen, defn.getPieces(), v.getValueQuantity(), false);
} else if (v.hasValueReference()) {
renderReference(q, gen, defn.getPieces(), v.getValueReference(), true);
} else if (v.hasValueAttachment()) {
// renderAttachment(gen, defn.getPieces(), v.getValueAttachment());
}
}
}
@ -528,8 +534,14 @@ public class QuestionnaireRenderer extends TerminologyRenderer {
defn.getPieces().add(gen.new Piece(null, " = ", null));
if (v.getValue().isPrimitive()) {
defn.getPieces().add(gen.new Piece(null, v.getValue().primitiveValue(), null));
} else {
} else if (v.hasValueCoding()) {
renderCoding(gen, defn.getPieces(), v.getValueCoding());
} else if (v.hasValueQuantity()) {
renderQuantity(gen, defn.getPieces(), v.getValueQuantity(), false);
} else if (v.hasValueReference()) {
renderReference(q, gen, defn.getPieces(), v.getValueReference(), false);
// } else if (v.hasValueAttachment()) {
// renderAttachment(gen, defn.getPieces(), v.getValueAttachment());
}
}
}
@ -759,8 +771,14 @@ public class QuestionnaireRenderer extends TerminologyRenderer {
if (first) first = false; else vi.tx(", ");
if (v.getValue().isPrimitive()) {
vi.tx(v.getValue().primitiveValue());
} else {
} else if (v.hasValueCoding()) {
renderCoding(vi, v.getValueCoding(), true);
} else if (v.hasValueReference()) {
renderReference(vi, v.getValueReference());
} else if (v.hasValueQuantity()) {
renderQuantity(vi, v.getValueQuantity());
// } else if (v.hasValueAttachment()) {
// renderAttachment(vi, v.getValueAttachment());
}
}
}

View File

@ -39,8 +39,10 @@ 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.utilities.Utilities;
import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator;
import org.hl7.fhir.utilities.xhtml.NodeType;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Piece;
public abstract class ResourceRenderer extends DataRenderer {
@ -216,6 +218,82 @@ public abstract class ResourceRenderer extends DataRenderer {
public void renderReference(ResourceWrapper rw, XhtmlNode x, Reference r) throws UnsupportedEncodingException, IOException {
renderReference(rw, x, r, true);
}
public void renderReference(Resource res, HierarchicalTableGenerator gen, List<Piece> pieces, Reference r, boolean allowLinks) throws UnsupportedEncodingException, IOException {
if (r == null) {
pieces.add(gen.new Piece(null, "null!", null));
return;
}
ResourceWrapper rw = new ResourceWrapperDirect(this.context, res);
ResourceWithReference tr = null;
String link = null;
StringBuilder text = new StringBuilder();
if (r.hasReferenceElement() && allowLinks) {
tr = resolveReference(rw, r.getReference());
if (!r.getReference().startsWith("#")) {
if (tr != null && tr.getReference() != null) {
link = tr.getReference();
} else if (r.getReference().contains("?")) {
text.append("Conditional Reference: ");
} else {
link = r.getReference();
}
}
}
if (tr != null && tr.getReference() != null && tr.getReference().startsWith("#")) {
text.append("See above (");
}
// what to display: if text is provided, then that. if the reference was resolved, then show the name, or the generated narrative
String display = r.hasDisplayElement() ? r.getDisplay() : null;
String name = tr != null && tr.getResource() != null ? tr.getResource().getNameFromResource() : null;
if (display == null && (tr == null || tr.getResource() == null)) {
if (!Utilities.noString(r.getReference())) {
text.append(r.getReference());
} else if (r.hasIdentifier()) {
text.append(displayIdentifier(r.getIdentifier()));
} else {
text.append("??");
}
} else if (context.isTechnicalMode()) {
text.append(r.getReference());
if (display != null) {
text.append(": "+display);
}
if ((tr == null || (tr.getReference() != null && !tr.getReference().startsWith("#"))) && name != null) {
text.append(" \""+name+"\"");
}
if (r.hasExtension(ToolingExtensions.EXT_TARGET_ID) || r.hasExtension(ToolingExtensions.EXT_TARGET_PATH)) {
text.append("(");
for (Extension ex : r.getExtensionsByUrl(ToolingExtensions.EXT_TARGET_ID)) {
if (ex.hasValue()) {
text.append(", ");
text.append("#"+ex.getValue().primitiveValue());
}
}
for (Extension ex : r.getExtensionsByUrl(ToolingExtensions.EXT_TARGET_PATH)) {
if (ex.hasValue()) {
text.append(", ");
text.append("/#"+ex.getValue().primitiveValue());
}
}
text.append(")");
}
} else {
if (display != null) {
text.append(display);
} else if (name != null) {
text.append(name);
} else {
text.append(". Description: (todo)");
}
}
if (tr != null && tr.getReference() != null && tr.getReference().startsWith("#")) {
text.append(")");
}
pieces.add(gen.new Piece(link,text.toString(), null));
}
public void renderReference(ResourceWrapper rw, XhtmlNode x, Reference r, boolean allowLinks) throws UnsupportedEncodingException, IOException {
if (r == null) {

View File

@ -172,6 +172,7 @@ public class BaseValidator implements IValidationContextResourceLoader {
protected boolean warnOnDraftOrExperimental;
protected Set<String> statusWarnings = new HashSet<>();
protected BestPracticeWarningLevel bpWarnings = BestPracticeWarningLevel.Warning;
protected String sessionId = Utilities.makeUuidLC();
public BaseValidator(IWorkerContext context, XVerExtensionManager xverManager, boolean debug) {
@ -1083,8 +1084,8 @@ public class BaseValidator implements IValidationContextResourceLoader {
String tt = extractResourceType(ref);
ok = VersionUtilities.getCanonicalResourceNames(context.getVersion()).contains(tt);
}
if (!ok && stack != null && !source.hasUserData("bundle.error.noted")) {
source.setUserData("bundle.error.noted", true);
if (!ok && stack != null && !sessionId.equals(source.getUserString("bundle.error.noted"))) {
source.setUserData("bundle.error.noted", sessionId);
hintOrError(!isWarning, errors, NO_RULE_DATE, IssueType.NOTFOUND, stack, false, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND, ref, name);
}
return null;
@ -1092,17 +1093,17 @@ public class BaseValidator implements IValidationContextResourceLoader {
if (fragment != null) {
int i = countFragmentMatches(el.get(0), fragment);
if (i == 0) {
source.setUserData("bundle.error.noted", true);
source.setUserData("bundle.error.noted", sessionId);
hintOrError(isNLLink, errors, NO_RULE_DATE, IssueType.NOTFOUND, stack, false, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND_FRAGMENT, ref, fragment, name);
} else if (i > 1) {
source.setUserData("bundle.error.noted", true);
source.setUserData("bundle.error.noted", sessionId);
rule(errors, "2023-11-15", IssueType.INVALID, stack, false, I18nConstants.BUNDLE_BUNDLE_ENTRY_FOUND_MULTIPLE_FRAGMENT, i, ref, fragment, name);
}
}
return el.get(0);
} else {
if (stack != null && !source.hasUserData("bundle.error.noted")) {
source.setUserData("bundle.error.noted", true);
if (stack != null && !sessionId.equals(source.getUserString("bundle.error.noted"))) {
source.setUserData("bundle.error.noted", sessionId);
rule(errors, "2023-11-15", IssueType.INVALID, stack, false, I18nConstants.BUNDLE_BUNDLE_ENTRY_FOUND_MULTIPLE, el.size(), ref, name);
}
return null;
@ -1118,8 +1119,8 @@ public class BaseValidator implements IValidationContextResourceLoader {
if (el.size() == 1) {
return el.get(0);
} else {
if (stack != null && !source.hasUserData("bundle.error.noted")) {
source.setUserData("bundle.error.noted", true);
if (stack != null && !sessionId.equals(source.getUserString("bundle.error.noted"))) {
source.setUserData("bundle.error.noted", sessionId);
rule(errors, "2023-11-15", IssueType.INVALID, stack, false, I18nConstants.BUNDLE_BUNDLE_ENTRY_FOUND_MULTIPLE, el.size(), ref, name);
}
return null;
@ -1140,17 +1141,17 @@ public class BaseValidator implements IValidationContextResourceLoader {
if (!VersionUtilities.isR4Plus(context.getVersion())) {
if (el.size() == 1) {
return el.get(0);
} else if (stack != null && !source.hasUserData("bundle.error.noted")) {
source.setUserData("bundle.error.noted", true);
} else if (stack != null && !sessionId.equals(source.getUserString("bundle.error.noted"))) {
source.setUserData("bundle.error.noted", sessionId);
rulePlural(errors, "2023-11-15", IssueType.INVALID, stack, false, el.size(), I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND_APPARENT, ref, name, CommaSeparatedStringBuilder.join(",", Utilities.sorted(tl)));
}
} else if (stack != null && !source.hasUserData("bundle.error.noted")) {
source.setUserData("bundle.error.noted", true);
} else if (stack != null && !sessionId.equals(source.getUserString("bundle.error.noted"))) {
source.setUserData("bundle.error.noted", sessionId);
rulePlural(errors, "2023-11-15", IssueType.INVALID, stack, false, el.size(), I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND_APPARENT, ref, name, CommaSeparatedStringBuilder.join(",", Utilities.sorted(tl)));
}
} else {
if (stack != null && !source.hasUserData("bundle.error.noted")) {
source.setUserData("bundle.error.noted", true);
if (stack != null && !sessionId.equals(source.getUserString("bundle.error.noted"))) {
source.setUserData("bundle.error.noted", sessionId);
hintOrError(!isWarning, errors, NO_RULE_DATE, IssueType.NOTFOUND, stack, false, I18nConstants.BUNDLE_BUNDLE_ENTRY_NOTFOUND, ref, name);
}
}

View File

@ -4311,7 +4311,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
StructureDefinition sdt = context.fetchTypeDefinition(type);
StructureDefinition tt = sdt;
while (tt != null) {
if (tt.getBaseDefinition().equals(sd.getUrl())) {
if (sd.getUrl().equals(tt.getBaseDefinition())) {
return sdt;
}
tt = context.fetchResource(StructureDefinition.class, tt.getBaseDefinition());

View File

@ -75,6 +75,8 @@ public class BundleValidator extends BaseValidator {
public boolean validateBundle(List<ValidationMessage> errors, Element bundle, NodeStack stack, boolean checkSpecials, ValidationContext hostContext, PercentageTracker pct, ValidationMode mode) {
boolean ok = true;
sessionId = Utilities.makeUuidLC();
String type = bundle.getNamedChildValue(TYPE, false);
type = StringUtils.defaultString(type);
List<Element> entries = new ArrayList<Element>();

View File

@ -574,7 +574,7 @@ public class StructureDefinitionValidator extends BaseValidator {
fpe.checkOnTypes(vc, rootPath, types, fpe.parse(exp), warnings);
} else {
StructureDefinition sd = context.fetchTypeDefinition(rootPath);
if (sd != null) {
if (sd != null && sd.getKind() == StructureDefinitionKind.RESOURCE) {
fpe.checkOnTypes(vc, rootPath, types, fpe.parse(exp), warnings);
} else {
fpe.checkOnTypes(vc, "DomainResource", types, fpe.parse(exp), warnings);