Merge pull request #1684 from hapifhir/2024-07-gg-rendering-work

2024 07 gg rendering work
This commit is contained in:
Grahame Grieve 2024-07-12 12:45:18 +08:00 committed by GitHub
commit e806a08ee2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 696 additions and 200 deletions

View File

@ -15,8 +15,18 @@ import org.hl7.fhir.utilities.xhtml.NodeType;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
/**
* This class is used to walk through the resources when rendering, whether
* the resource is a native resource or loaded by the element model
* An R4 wrapper for the R5 rendering framework - use this to feed R4 resources directly
* into the R5 framework.
*
* The R5 framework is fine to render R4 resources, and has R4 (etc) specific code where
* appropriate (or will be modified to do so).
*
* Note that in order to use this, you need an R5 IWorkerContext. You can create a
* R5 SimpleWorkerContext and load it with all the definitions from R4 (that's how the
* validator works internally, so this is well tested code). But you only need to set
* up the R5 context once; then you can create instances of these to wrap the objects you
* want rendered on the fly. (is thread safe)
*
*/
public class ResourceWrapperR4 extends ResourceWrapper {

View File

@ -15,8 +15,18 @@ import org.hl7.fhir.utilities.xhtml.NodeType;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
/**
* This class is used to walk through the resources when rendering, whether
* the resource is a native resource or loaded by the element model
* An R4 wrapper for the R5 rendering framework - use this to feed R4 resources directly
* into the R5 framework.
*
* The R5 framework is fine to render R4 resources, and has R4 (etc) specific code where
* appropriate (or will be modified to do so).
*
* Note that in order to use this, you need an R5 IWorkerContext. You can create a
* R5 SimpleWorkerContext and load it with all the definitions from R4 (that's how the
* validator works internally, so this is well tested code). But you only need to set
* up the R5 context once; then you can create instances of these to wrap the objects you
* want rendered on the fly. (is thread safe)
*
*/
public class ResourceWrapperR4B extends ResourceWrapper {

View File

@ -343,6 +343,24 @@ public class Element extends Base implements NamedItem {
}
}
public void setChildValue(String name, Base value) {
if (children == null)
children = new NamedItemList<Element>();
for (Element child : children) {
if (name.equals(child.getName())) {
if (!child.isPrimitive())
throw new Error("Cannot set a value of a non-primitive type ("+name+" on "+this.getName()+")");
child.setValue(value.primitiveValue());
}
}
try {
setProperty(name.hashCode(), name, value);
} catch (FHIRException e) {
throw new Error(e);
}
}
public List<Element> getChildren(String name) {
List<Element> res = new ArrayList<Element>();
if (children.size() > 20) {
@ -478,6 +496,11 @@ public class Element extends Base implements NamedItem {
children.add(i, ne);
childForValue = ne;
break;
} else if (p.getName().endsWith("[x]") && name.startsWith(p.getName().replace("[x]", ""))) {
Element ne = new Element(p.getName(), p).setFormat(format);
children.add(i, ne);
childForValue = ne;
break;
}
}
@ -485,7 +508,7 @@ public class Element extends Base implements NamedItem {
throw new Error("Cannot set property "+name+" on "+this.name);
else if (value.isPrimitive()) {
if (childForValue.property.getName().endsWith("[x]"))
childForValue.name = name+Utilities.capitalize(value.fhirType());
childForValue.name = childForValue.name.replace("[x]", "")+Utilities.capitalize(value.fhirType());
childForValue.setValue(value.primitiveValue());
} else {
Element ve = (Element) value;
@ -693,6 +716,7 @@ public class Element extends Base implements NamedItem {
public Element getNamedChild(String name) {
return getNamedChild(name, true);
}
public Element getNamedChild(String name, boolean exception) {
if (children == null)
return null;
@ -1163,7 +1187,9 @@ public class Element extends Base implements NamedItem {
}
public void removeChild(String name) {
children.removeIf(n -> name.equals(n.getName()));
if (children.removeIf(n -> name.equals(n.getName()))) {
children.clearMap();
}
}
public boolean isProhibited() {

View File

@ -641,7 +641,7 @@ public class Property {
public boolean isTranslatable() {
boolean ok = ToolingExtensions.readBoolExtension(definition, ToolingExtensions.EXT_TRANSLATABLE);
if (!ok && !definition.getPath().endsWith(".id") && !Utilities.existsInList(definition.getBase().getPath(), "Resource.id", "Reference.reference", "Coding.version", "Identifier.value", "SampledData.offsets", "SampledData.data", "ContactPoint.value")) {
if (!ok && !definition.getPath().endsWith(".id") && !definition.getPath().endsWith(".linkId") && !Utilities.existsInList(definition.getBase().getPath(), "Resource.id", "Reference.reference", "Coding.version", "Identifier.value", "SampledData.offsets", "SampledData.data", "ContactPoint.value")) {
String t = getType();
ok = Utilities.existsInList(t, "string", "markdown");
}

View File

@ -24,13 +24,9 @@ public class ActorDefinitionRenderer extends ResourceRenderer {
@Override
public void buildNarrative(RenderingStatus status, XhtmlNode x, ResourceWrapper r) throws FHIRFormatError, DefinitionException, IOException, FHIRException, EOperationOutcome {
if (r.isDirect()) {
renderResourceTechDetails(r, x);
genSummaryTable(status, x, (ActorDefinition) r.getBase());
render(status, x, (ActorDefinition) r.getBase(), r);
} else {
throw new Error("ActorDefinitionRenderer only renders native resources directly");
}
renderResourceTechDetails(r, x);
genSummaryTable(status, x, r);
render(status, x, r);
}
@Override
@ -38,35 +34,35 @@ public class ActorDefinitionRenderer extends ResourceRenderer {
return canonicalTitle(r);
}
public void render(RenderingStatus status, XhtmlNode x, ActorDefinition acd, ResourceWrapper r) throws FHIRFormatError, DefinitionException, IOException {
public void render(RenderingStatus status, XhtmlNode x, ResourceWrapper acd) throws FHIRFormatError, DefinitionException, IOException {
XhtmlNode tbl = x.table("grid");
XhtmlNode tr = tbl.tr();
tr.td().b().tx(context.formatPhrase(RenderingContext.ACTOR_DEF_ACT, acd.getName()) + " ");
tr.td().tx(acd.getTitle());
tr.td().tx(context.formatPhrase(RenderingContext.ACTOR_DEF_TYP, acd.getType().toCode()) + " ");
tr.td().b().tx(context.formatPhrase(RenderingContext.ACTOR_DEF_ACT, context.getTranslated(acd.child("name"))) + " ");
tr.td().tx(context.getTranslated(acd.child("title")));
tr.td().tx(context.formatPhrase(RenderingContext.ACTOR_DEF_TYP, acd.primitiveValue("type")) + " ");
XhtmlNode td = tbl.tr().td().colspan("3");
addMarkdown(td, acd.getDocumentation());
if (acd.hasReference()) {
addMarkdown(td, context.getTranslated(acd.child("documentation")));
if (acd.has("reference")) {
tbl.tr().td().tx(context.formatPhrase(RenderingContext.GENERAL_REFS));
td = tr.td().colspan("2");
boolean first = true;
for (UrlType t : acd.getReference()) {
for (ResourceWrapper t : acd.children("reference")) {
if (first) first = false; else x.br();
renderUri(status, td, wrapWC(r, t));
renderUri(status, td, t);
}
}
if (acd.hasCapabilities()) {
if (acd.has("capabilities")) {
tbl.tr().td().tx(context.formatPhrase(RenderingContext.ACTOR_DEF_CAP));
td = tr.td().colspan("2");
renderCanonical(status, r, td, CapabilityStatement.class, acd.getCapabilitiesElement());
renderCanonical(status, td, acd.child("capabilities"));
}
if (acd.hasDerivedFrom()) {
if (acd.has("derivedFrom")) {
tbl.tr().td().tx(context.formatPhrase(RenderingContext.ACTOR_DEF_DER));
td = tr.td().colspan("2");
boolean first = true;
for (UrlType t : acd.getReference()) {
for (ResourceWrapper t : acd.children("reference")) {
if (first) first = false; else x.br();
renderUri(status, r, td, t);
renderUri(status, td, t);
}
}
}

View File

@ -69,7 +69,11 @@ public class BundleRenderer extends ResourceRenderer {
if (id != null && !context.hasAnchor(anchor)) {
context.addAnchor(anchor);
root.an(context.prefixAnchor(anchor));
root.an(context.prefixAnchor("hc"+anchor));
}
anchor = "hc"+anchor;
if (id != null && !context.hasAnchor(anchor)) {
context.addAnchor(anchor);
root.an(context.prefixAnchor(anchor));
}
}
root.hr();
@ -100,8 +104,10 @@ public class BundleRenderer extends ResourceRenderer {
xn = new XhtmlNode();
xn.para().b().tx(context.formatPhrase(RenderingContext.BUNDLE_REV_EXCP, e.getMessage()) + " ");
}
} else {
xn.stripAnchorsByName(context.getAnchors());
}
root.blockquote().para().addChildren(xn);
root.blockquote().addChildren(xn);
}
if (be.has("request")) {
renderRequest(x, be.child("request"));

View File

@ -1830,7 +1830,7 @@ public class DataRenderer extends Renderer implements CodeResolver {
x.addText(q.child("high").primitiveValue("value").toString());
else
x.tx("?");
if (q.child("low").has("unit"))
if (q.has("low") && q.child("low").has("unit"))
x.tx(" "+q.child("low").child("unit"));
}
@ -2071,7 +2071,7 @@ public class DataRenderer extends Renderer implements CodeResolver {
private boolean renderExpression(CommaSeparatedStringBuilder c, ResourceWrapper p) {
ResourceWrapper exp = p.extensionValue("http://hl7.org/fhir/StructureDefinition/cqf-expression");
if (exp == null) {
if (exp == null || !exp.has("value")) {
return false;
}
c.append(exp.child("value").primitiveValue("expression"));

View File

@ -52,8 +52,10 @@ public class ProfileDrivenRenderer extends ResourceRenderer {
generateByProfile(status, r, sd, r, sd.getSnapshot().getElement(), ed, context.getProfileUtilities().getChildList(sd, ed), x, r.fhirType(), context.isTechnicalMode(), 0);
}
} catch (Exception e) {
System.out.println(context.formatPhrase(RenderingContext.PROF_DRIV_ERR_GEN_NARR) +r.fhirType()+"/"+r.getId()+": "+e.getMessage());
e.printStackTrace();
if (DEBUG) {
System.out.println(context.formatPhrase(RenderingContext.PROF_DRIV_ERR_GEN_NARR) +r.fhirType()+"/"+r.getId()+": "+e.getMessage());
e.printStackTrace();
}
x.para().b().style("color: maroon").tx(context.formatPhrase(RenderingContext.PROF_DRIV_EXCP, e.getMessage())+" ");
}
}

View File

@ -362,7 +362,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer {
defn.getPieces().add(gen.new Piece(null, (context.formatPhrase(RenderingContext.QUEST_OPTIONS)+" "), null));
if (context.getDefinitionsTarget() == null) {
// if we don't have a definitions target, we'll add them below.
defn.getPieces().add(gen.new Piece("#opt-item."+i.primitiveValue("linkId"), Integer.toString(i.children("answerOption").size())+" "+Utilities.pluralize("option", i.children("answerOption").size()), null));
defn.getPieces().add(gen.new Piece("#"+context.prefixAnchor("opt-item."+i.primitiveValue("linkId")), Integer.toString(i.children("answerOption").size())+" "+Utilities.pluralize("option", i.children("answerOption").size()), null));
} else {
defn.getPieces().add(gen.new Piece(context.getDefinitionsTarget()+"#item."+i.primitiveValue("linkId"), Integer.toString(i.children("answerOption").size())+" "+Utilities.pluralize("option", i.children("answerOption").size()), null));
}

View File

@ -40,6 +40,8 @@ import org.hl7.fhir.utilities.xhtml.XhtmlNode;
*/
public class Renderer {
protected static final boolean DEBUG = false;
public static class RenderingStatus {
private boolean extensions;

View File

@ -245,7 +245,6 @@ public abstract class ResourceRenderer extends DataRenderer {
actual = type;
}
if (actual != null && actual.hasPrimitiveValue()) {
System.out.println("displayReference: "+actual);
if ("#".equals(actual.primitiveValue())) {
return "this resource";
} else {
@ -344,9 +343,12 @@ public abstract class ResourceRenderer extends DataRenderer {
} else if (rr.getResource() == null) {
String disp = display != null && display.hasPrimitiveValue() ? displayDataType(display) : "??";
x.ah(context.prefixLocalHref(rr.getWebPath())).tx(disp);
} else {
} else if (rr.getResource() != null) {
String disp = display != null && display.hasPrimitiveValue() ? displayDataType(display) : RendererFactory.factory(rr.getResource(), context.forContained()).buildSummary(rr.getResource());
x.ah(context.prefixLocalHref(rr.getWebPath())).tx(disp);
} else {
String disp = display != null && display.hasPrimitiveValue() ? displayDataType(display) : "??";
x.ah(context.prefixLocalHref(rr.getWebPath())).tx(disp);
}
} else if (display != null && id != null) {
renderDataType(status, x, display);
@ -829,12 +831,24 @@ public abstract class ResourceRenderer extends DataRenderer {
// first thing we do is lay down the resource anchors.
if (!Utilities.noString(r.getId())) {
if (!context.isSecondaryLang()) {
x.an(context.prefixAnchor(r.getScopedId()));
x.an(context.prefixAnchor("hc"+r.getScopedId()));
String sid = r.getScopedId();
if (!context.hasAnchor(sid)) {
context.addAnchor(sid);
x.an(context.prefixAnchor(sid));
}
sid = "hc"+sid;
if (!context.hasAnchor(sid)) {
context.addAnchor(sid);
x.an(context.prefixAnchor(sid));
}
}
if (context.getLocale() != null) {
String langSuffix = "-"+context.getLocale().toLanguageTag();
x.an(context.prefixAnchor("hc"+r.getScopedId()+langSuffix));
String sid = r.getScopedId()+langSuffix;
if (!context.hasAnchor(sid)) {
context.addAnchor(sid);
x.an(context.prefixAnchor(sid));
}
}
}
@ -1050,6 +1064,99 @@ public abstract class ResourceRenderer extends DataRenderer {
}
}
public void genSummaryTable(RenderingStatus status, XhtmlNode x, ResourceWrapper cr) throws IOException {
if (context.isShowSummaryTable() && cr != null) {
XhtmlNode tbl = x.table("grid");
genSummaryTableContent(status, tbl, cr);
}
}
protected void genSummaryTableContent(RenderingStatus status, XhtmlNode tbl, ResourceWrapper cr) throws IOException {
XhtmlNode tr;
if (cr.has("url")) {
tr = tbl.tr();
tr.td().tx(context.formatPhrase(RenderingContext.GENERAL_DEFINING_URL)+":");
tr.td().code().tx(cr.primitiveValue("url"));
} else if (cr.hasExtension("http://hl7.org/fhir/5.0/StructureDefinition/extension-NamingSystem.url")) {
status.setExtensions(true);
tr = tbl.tr();
tr.td().tx(context.formatPhrase(RenderingContext.GENERAL_DEFINING_URL)+":");
tr.td().code().tx(cr.extensionString("http://hl7.org/fhir/5.0/StructureDefinition/extension-NamingSystem.url"));
} else if (!context.isContained()) {
tr = tbl.tr();
tr.td().tx(context.formatPhrase(RenderingContext.GENERAL_DEFINING_URL));
tr.td();
}
if (cr.has("version")) {
tr = tbl.tr();
tr.td().tx(context.formatPhrase(RenderingContext.GENERAL_VER)+":");
renderDataType(status, tr.td(), cr.child("version"));
} else if (cr.hasExtension("http://terminology.hl7.org/StructureDefinition/ext-namingsystem-version")) {
status.setExtensions(true);
tr = tbl.tr();
tr.td().tx(context.formatPhrase(RenderingContext.GENERAL_VER)+":");
renderDataType(status, tr.td(), cr.extensionValue("http://hl7.org/fhir/5.0/StructureDefinition/extension-NamingSystem.version"));
}
String name = context.getTranslated(cr.child("name"));
String title = context.getTranslated(cr.child("title"));
if (name != null) {
tr = tbl.tr();
tr.td().tx(context.formatPhrase(RenderingContext.GENERAL_NAME)+":");
tr.td().tx(name);
}
if (title != null && !title.equalsIgnoreCase(name)) {
tr = tbl.tr();
tr.td().tx(context.formatPhrase(RenderingContext.GENERAL_TITLE)+":");
tr.td().tx(title);
}
if (cr.has("status") && !context.isContained()) {
tr = tbl.tr();
tr.td().tx(context.formatPhrase(RenderingContext.GENERAL_STATUS)+":");
tr.td().tx(describeStatus(status, cr));
}
if (cr.has("description")) {
tr = tbl.tr();
tr.td().tx(context.formatPhrase(RenderingContext.GENERAL_DEFINITION)+":");
tr.td().markdown(context.getTranslated(cr.child("description")), "description");
}
if (cr.has("publisher")) {
tr = tbl.tr();
tr.td().tx(context.formatPhrase(RenderingContext.CANON_REND_PUBLISHER)+":");
buildPublisherLinks( tr.td(), cr);
}
if (cr.hasExtension(ToolingExtensions.EXT_WORKGROUP)) {
status.setExtensions(true);
tr = tbl.tr();
tr.td().tx(context.formatPhrase(RenderingContext.CANON_REND_COMMITTEE)+":");
renderCommitteeLink(tr.td(), cr);
}
if (cr.has("copyright")) {
tr = tbl.tr();
tr.td().tx(context.formatPhrase(RenderingContext.GENERAL_COPYRIGHT)+":");
tr.td().markdown(context.getTranslated(cr.child("copyright")), "copyright");
}
if (cr.hasExtension(ToolingExtensions.EXT_FMM_LEVEL)) {
status.setExtensions(true);
// Use hard-coded spec link to point to current spec because DSTU2 had maturity listed on a different page
tr = tbl.tr();
tr.td().ah("http://hl7.org/fhir/versions.html#maturity", "Maturity Level").attribute("class", "fmm").tx(context.formatPhrase(RenderingContext.CANON_REND_COMMITTEE)+":");
renderDataType(status, tr.td(), cr.extensionValue(ToolingExtensions.EXT_FMM_LEVEL));
}
}
public void genSummaryTable(RenderingStatus status, XhtmlNode x, CanonicalResource cr) throws IOException {
if (context.isShowSummaryTable() && cr != null) {
XhtmlNode tbl = x.table("grid");
@ -1063,12 +1170,12 @@ public abstract class ResourceRenderer extends DataRenderer {
if (cr.hasUrl()) {
tr = tbl.tr();
tr.td().tx(context.formatPhrase(RenderingContext.GENERAL_DEFINING_URL)+":");
tr.td().tx(cr.getUrl());
tr.td().code().tx(cr.getUrl());
} else if (cr.hasExtension("http://hl7.org/fhir/5.0/StructureDefinition/extension-NamingSystem.url")) {
status.setExtensions(true);
tr = tbl.tr();
tr.td().tx(context.formatPhrase(RenderingContext.GENERAL_DEFINING_URL));
tr.td().tx(ToolingExtensions.readStringExtension(cr, "http://hl7.org/fhir/5.0/StructureDefinition/extension-NamingSystem.url")+":");
tr.td().code().tx(ToolingExtensions.readStringExtension(cr, "http://hl7.org/fhir/5.0/StructureDefinition/extension-NamingSystem.url")+":");
} else if (!context.isContained()) {
tr = tbl.tr();
tr.td().tx(context.formatPhrase(RenderingContext.GENERAL_DEFINING_URL));
@ -1115,14 +1222,14 @@ public abstract class ResourceRenderer extends DataRenderer {
if (cr.hasPublisher()) {
tr = tbl.tr();
tr.td().tx(context.formatPhrase(RenderingContext.CANON_REND_PUBLISHER)+":");
tr.td().tx(buildPublisherLinks(cr));
buildPublisherLinks(tr.td(), cr);
}
if (cr.hasExtension(ToolingExtensions.EXT_WORKGROUP)) {
status.setExtensions(true);
tr = tbl.tr();
tr.td().tx(context.formatPhrase(RenderingContext.CANON_REND_COMMITTEE)+":");
tr.td().tx(renderCommitteeLink(cr));
renderCommitteeLink(tr.td(), cr);
}
if (cr.hasCopyright()) {
@ -1141,68 +1248,137 @@ public abstract class ResourceRenderer extends DataRenderer {
}
protected String renderCommitteeLink(CanonicalResource cr) {
String code = ToolingExtensions.readStringExtension(cr, ToolingExtensions.EXT_WORKGROUP);
protected void renderCommitteeLink(XhtmlNode x, ResourceWrapper cr) {
String code = cr.extensionString(ToolingExtensions.EXT_WORKGROUP);
CodeSystem cs = context.getContext().fetchCodeSystem("http://terminology.hl7.org/CodeSystem/hl7-work-group");
if (cs == null || !cs.hasWebPath())
return code;
x.tx(code);
else {
ConceptDefinitionComponent cd = CodeSystemUtilities.findCode(cs.getConcept(), code);
if (cd == null) {
return code;
x.tx(code);
} else {
return "<a href=\""+cs.getWebPath()+"#"+cs.getId()+"-"+cd.getCode()+"\">"+cd.getDisplay()+"</a>";
x.ah(cs.getWebPath()+"#"+cs.getId()+"-"+cd.getCode()).tx(cd.getDisplay());
}
}
}
private String buildPublisherLinks(CanonicalResource cr) {
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(". ");
private void buildPublisherLinks(XhtmlNode x, CanonicalResource cr) {
boolean useName = false;
for (ContactDetail cd : cr.getContact()) {
if (!cd.hasName()) {
useName = true;
}
}
boolean first = true;
if (!useName) {
b.append(Utilities.escapeXml(cr.getPublisher()));
x.tx(Utilities.escapeXml(cr.getPublisher()));
first = false;
}
for (ContactDetail cd : cr.getContact()) {
String name = cd.hasName() ? cd.getName() : cr.getPublisher();
b.append(renderContact(name, cd.getTelecom()));
if (cd.hasTelecom()) {
if (first) first = false; else x.tx(". ");
renderContact(x, name, cd.getTelecom());
}
}
return b.toString();
}
private String renderContact(String name, List<ContactPoint> telecom) {
private void buildPublisherLinks(XhtmlNode x, ResourceWrapper cr) {
boolean useName = false;
for (ResourceWrapper cd : cr.children("contact")) {
if (!cd.has("name")) {
useName = true;
}
}
boolean first = true;
if (!useName) {
x.tx(Utilities.escapeXml(cr.primitiveValue("publisher")));
first = false;
}
for (ResourceWrapper cd : cr.children("contact")) {
String name = cd.has("name") ? cd.primitiveValue("name") : cr.primitiveValue("publisher");
if (cd.has("telecom")) {
if (first) first = false; else x.tx(". ");
renderContactW(x, name, cd.children("telecom"));
}
}
}
private void renderContactW(XhtmlNode x, String name, List<ResourceWrapper> telecom) {
List<String> urls = new ArrayList<>();
for (ResourceWrapper t : telecom) {
if ("url".equals(t.primitiveValue()) && t.has("value")) {
urls.add(t.primitiveValue("value"));
}
}
if (urls.size() == 1) {
x.ah(urls.get(0)).tx(name);
} else { // if (urls.size() == 0) {
x.tx(name);
}
for (ResourceWrapper t : telecom) {
String system = t.primitiveValue("system");
String value = t.primitiveValue("value");
if ("url".equals(system) && value != null && urls.size() != 1) {
x.tx(", ");
x.ah(t.primitiveValue("value")).tx("Link");
}
if ("email".equals(system) && value != null) {
x.tx(", ");
x.ah("mailto:"+t.primitiveValue("value")).tx("Email");
}
if ("phone".equals(system) && value != null) {
x.tx(", ");
x.tx(t.primitiveValue("value"));
}
if ("fax".equals(system) && value != null) {
x.tx(", ");
x.tx("Fax:"+t.primitiveValue("value"));
}
}
}
private void renderContact(XhtmlNode x, String name, List<ContactPoint> telecom) {
List<String> urls = new ArrayList<>();
for (ContactPoint t : telecom) {
if (t.getSystem() == ContactPointSystem.URL && t.hasValue()) {
urls.add(t.getValue());
}
}
StringBuilder b = new StringBuilder();
if (urls.size() == 1) {
b.append("<a href=\""+Utilities.escapeXml(urls.get(0))+"\">"+Utilities.escapeXml(name)+"</a>");
} else if (urls.size() == 1) {
b.append(Utilities.escapeXml(name));
x.ah(urls.get(0)).tx(name);
} else { // if (urls.size() == 0) {
x.tx(name);
}
for (ContactPoint t : telecom) {
b.append(", ");
if (t.getSystem() == ContactPointSystem.URL && t.hasValue() && urls.size() > 1) {
b.append("<a href=\""+Utilities.escapeXml(t.getValue())+"\">Link</a>");
if (t.getSystem() == ContactPointSystem.URL && t.hasValue() && urls.size() != 1) {
x.tx(", ");
x.ah(t.getValue()).tx("Link");
}
if (t.getSystem() == ContactPointSystem.EMAIL && t.hasValue()) {
b.append("<a href=\"mailto:"+Utilities.escapeXml(t.getValue())+"\">Email</a>");
x.tx(", ");
x.ah("mailto:"+t.getValue()).tx("Email");
}
if (t.getSystem() == ContactPointSystem.PHONE && t.hasValue()) {
b.append(Utilities.escapeXml(t.getValue()));
x.tx(", ");
x.tx(t.getValue());
}
if (t.getSystem() == ContactPointSystem.FAX && t.hasValue()) {
b.append("Fax:"+Utilities.escapeXml(t.getValue()));
x.tx(", ");
x.tx("Fax:"+t.getValue());
}
}
return b.toString();
}
protected String describeStatus(RenderingStatus status, ResourceWrapper cr) {
String s = describeStatus(cr.primitiveValue("status"), cr.primitiveValue("experimental"), cr.child("date"), cr.extensionString("http://hl7.org/fhir/StructureDefinition/valueset-deprecated"));
if (cr.hasExtension(ToolingExtensions.EXT_STANDARDS_STATUS)) {
status.setExtensions(true);
s = s + presentStandardsStatus(cr.extensionString(ToolingExtensions.EXT_STANDARDS_STATUS));
}
return s;
}
protected String describeStatus(RenderingStatus status, CanonicalResource cr) {
@ -1245,4 +1421,21 @@ public abstract class ResourceRenderer extends DataRenderer {
}
}
protected String describeStatus(String status, String experimental, ResourceWrapper dt, String deprecated) {
String sfx = dt != null ? " as of "+displayDataType(dt) : "";
if ("true".equals(deprecated)) {
if ("retired".equals(status)) {
return "Deprecated + Retired"+sfx;
} else {
return "Deprecated"+sfx;
}
} else {
switch (status) {
case "active": return ("true".equals(experimental) ? "Experimental" : "Active")+sfx;
case "draft": return "Draft"+sfx;
case "retired": return "Retired"+sfx;
default: return "Unknown"+sfx;
}
}
}
}

View File

@ -2779,7 +2779,9 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
} else {
StructureDefinition sd = context.getWorker().fetchTypeDefinition(t);
if (sd == null) {
System.out.println("Unable to find "+t);
if (DEBUG) {
System.out.println("Unable to find "+t);
}
sd = context.getWorker().fetchTypeDefinition(t);
} else if (sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE) {
used = true;

View File

@ -31,7 +31,6 @@ import org.hl7.fhir.utilities.xhtml.XhtmlNode;
public abstract class TerminologyRenderer extends ResourceRenderer {
private static final boolean DEBUG = false;
public TerminologyRenderer(RenderingContext context) {

View File

@ -1012,4 +1012,8 @@ public class RenderingContext extends RenderingI18nContext {
public void addAnchor(String anchor) {
anchors.add(anchor);
}
public Set<String> getAnchors() {
return anchors;
}
}

View File

@ -4,6 +4,7 @@ import java.util.List;
import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.CodeType;
import org.hl7.fhir.r5.model.CompartmentDefinition;
import org.hl7.fhir.r5.model.Constants;
import org.hl7.fhir.r5.model.ContactDetail;
@ -71,9 +72,9 @@ public class CanonicalResourceUtilities {
ext = res.addElement("extension");
ext.setChildValue("url", ToolingExtensions.EXT_WORKGROUP);
}
ext.setChildValue("valueCode", code);
ext.setChildValue("valueCode", new CodeType(code));
res.setChildValue("publisher", "HL7 International / "+wg.getName());
while (res.hasChild("contact")) {
while (res.hasChildren("contact")) {
res.removeChild("contact");
}
Element c = res.addElement("contact");
@ -82,96 +83,96 @@ public class CanonicalResourceUtilities {
t.setChildValue("value", wg.getLink());
}
}
/**
* for use in the core build where the context is not fully populated. Only known safe for R6 resources
*
* @param res
* @param code
*/
public static void setHl7WG(org.w3c.dom.Element res, String code) {
String rt = res.getNodeName();
if (VersionUtilities.getExtendedCanonicalResourceNames("5.0.0").contains(rt)) {
var wg = HL7WorkGroups.find(code);
if (wg == null) {
throw new Error("Unknown WG "+code);
}
List<org.w3c.dom.Element> extensions = XMLUtil.getNamedChildren(res, "extension");
org.w3c.dom.Element wgext = null;
for (org.w3c.dom.Element ext : extensions) {
String url = ext.getAttribute("url");
if (ToolingExtensions.EXT_WORKGROUP.equals(url)) {
wgext = ext;
}
}
if (wgext == null) {
wgext = res.getOwnerDocument().createElementNS(Constants.NS_FHIR_ROOT, "extension");
wgext.setAttribute("url", ToolingExtensions.EXT_WORKGROUP);
org.w3c.dom.Element after = XMLUtil.getLastChild(res, "id", "meta", "text", "implicitRules", "language", "text", "contained");
if (after != null) {
after = XMLUtil.getNextSibling(after);
}
res.insertBefore(wgext, after);
res.insertBefore(res.getOwnerDocument().createTextNode("\n "), after);
}
XMLUtil.clearChildren(wgext);
org.w3c.dom.Element valueCode = res.getOwnerDocument().createElementNS(Constants.NS_FHIR_ROOT, "valueCode");
wgext.appendChild(valueCode);
valueCode.setAttribute("value", code);
org.w3c.dom.Element pub = XMLUtil.getNamedChild(res, "publisher");
if (pub == null) {
pub = res.getOwnerDocument().createElementNS(Constants.NS_FHIR_ROOT, "publisher");
org.w3c.dom.Element after = XMLUtil.getLastChild(res, "id", "meta", "text", "implicitRules", "language", "text", "contained", "extension", "modifierExtension",
"url", "identifier", "version", "versionAlgorithmString", "versionAlgorithmCoding", "name", "title", "status", "experimental", "date", ("EvidenceReport".equals(rt) ? "subject" : "xx"));
if (after != null) {
after = XMLUtil.getNextSibling(after);
}
res.insertBefore(pub, after);
res.insertBefore(res.getOwnerDocument().createTextNode("\n "), after);
}
pub.setAttribute("value", "HL7 International / "+wg.getName());
org.w3c.dom.Element contact = XMLUtil.getNamedChild(res, "contact");
if (contact == null) {
contact = res.getOwnerDocument().createElementNS(Constants.NS_FHIR_ROOT, "contact");
res.insertBefore(contact, XMLUtil.getNextSibling(pub));
res.insertBefore(res.getOwnerDocument().createTextNode("\n "), contact.getNextSibling());
}
org.w3c.dom.Element telecom = XMLUtil.getNamedChild(contact, "telecom");
if (telecom == null) {
contact.appendChild(res.getOwnerDocument().createTextNode("\n "));
telecom = res.getOwnerDocument().createElementNS(Constants.NS_FHIR_ROOT, "telecom");
contact.appendChild(telecom);
contact.appendChild(res.getOwnerDocument().createTextNode("\n "));
}
org.w3c.dom.Element system = XMLUtil.getNamedChild(telecom, "system");
if (system == null) {
system = res.getOwnerDocument().createElementNS(Constants.NS_FHIR_ROOT, "system");
org.w3c.dom.Element after = XMLUtil.getLastChild(telecom, "id", "extension");
if (after != null) {
after = XMLUtil.getNextSibling(after);
}
telecom.insertBefore(system, after);
telecom.insertBefore(res.getOwnerDocument().createTextNode("\n "), after);
}
system.setAttribute("value", "url");
org.w3c.dom.Element value = XMLUtil.getNamedChild(telecom, "value");
if (value == null) {
value = res.getOwnerDocument().createElementNS(Constants.NS_FHIR_ROOT, "value");
org.w3c.dom.Element after = XMLUtil.getLastChild(telecom, "id", "extension", "system");
if (after != null) {
after = XMLUtil.getNextSibling(after);
}
telecom.insertBefore(system, after);
telecom.insertBefore(res.getOwnerDocument().createTextNode("\n "), after);
}
value.setAttribute("value", wg.getLink());
}
}
//
// /**
// * for use in the core build where the context is not fully populated. Only known safe for R6 resources
// *
// * @param res
// * @param code
// */
// public static void setHl7WG(org.w3c.dom.Element res, String code) {
// String rt = res.getNodeName();
// if (VersionUtilities.getExtendedCanonicalResourceNames("5.0.0").contains(rt)) {
// var wg = HL7WorkGroups.find(code);
// if (wg == null) {
// throw new Error("Unknown WG "+code);
// }
//
// List<org.w3c.dom.Element> extensions = XMLUtil.getNamedChildren(res, "extension");
// org.w3c.dom.Element wgext = null;
// for (org.w3c.dom.Element ext : extensions) {
// String url = ext.getAttribute("url");
// if (ToolingExtensions.EXT_WORKGROUP.equals(url)) {
// wgext = ext;
// }
// }
// if (wgext == null) {
// wgext = res.getOwnerDocument().createElementNS(Constants.NS_FHIR_ROOT, "extension");
// wgext.setAttribute("url", ToolingExtensions.EXT_WORKGROUP);
// org.w3c.dom.Element after = XMLUtil.getLastChild(res, "id", "meta", "text", "implicitRules", "language", "text", "contained");
// if (after != null) {
// after = XMLUtil.getNextSibling(after);
// }
// res.insertBefore(wgext, after);
// res.insertBefore(res.getOwnerDocument().createTextNode("\n "), after);
// }
// XMLUtil.clearChildren(wgext);
// org.w3c.dom.Element valueCode = res.getOwnerDocument().createElementNS(Constants.NS_FHIR_ROOT, "valueCode");
// wgext.appendChild(valueCode);
// valueCode.setAttribute("value", code);
//
// org.w3c.dom.Element pub = XMLUtil.getNamedChild(res, "publisher");
// if (pub == null) {
// pub = res.getOwnerDocument().createElementNS(Constants.NS_FHIR_ROOT, "publisher");
// org.w3c.dom.Element after = XMLUtil.getLastChild(res, "id", "meta", "text", "implicitRules", "language", "text", "contained", "extension", "modifierExtension",
// "url", "identifier", "version", "versionAlgorithmString", "versionAlgorithmCoding", "name", "title", "status", "experimental", "date", ("EvidenceReport".equals(rt) ? "subject" : "xx"));
// if (after != null) {
// after = XMLUtil.getNextSibling(after);
// }
// res.insertBefore(pub, after);
// res.insertBefore(res.getOwnerDocument().createTextNode("\n "), after);
// }
// pub.setAttribute("value", "HL7 International / "+wg.getName());
//
// org.w3c.dom.Element contact = XMLUtil.getNamedChild(res, "contact");
// if (contact == null) {
// contact = res.getOwnerDocument().createElementNS(Constants.NS_FHIR_ROOT, "contact");
// res.insertBefore(contact, XMLUtil.getNextSibling(pub));
// res.insertBefore(res.getOwnerDocument().createTextNode("\n "), contact.getNextSibling());
// }
//
// org.w3c.dom.Element telecom = XMLUtil.getNamedChild(contact, "telecom");
// if (telecom == null) {
// contact.appendChild(res.getOwnerDocument().createTextNode("\n "));
// telecom = res.getOwnerDocument().createElementNS(Constants.NS_FHIR_ROOT, "telecom");
// contact.appendChild(telecom);
// contact.appendChild(res.getOwnerDocument().createTextNode("\n "));
// }
//
// org.w3c.dom.Element system = XMLUtil.getNamedChild(telecom, "system");
// if (system == null) {
// system = res.getOwnerDocument().createElementNS(Constants.NS_FHIR_ROOT, "system");
// org.w3c.dom.Element after = XMLUtil.getLastChild(telecom, "id", "extension");
// if (after != null) {
// after = XMLUtil.getNextSibling(after);
// }
// telecom.insertBefore(system, after);
// telecom.insertBefore(res.getOwnerDocument().createTextNode("\n "), after);
// }
// system.setAttribute("value", "url");
//
//
// org.w3c.dom.Element value = XMLUtil.getNamedChild(telecom, "value");
// if (value == null) {
// value = res.getOwnerDocument().createElementNS(Constants.NS_FHIR_ROOT, "value");
// org.w3c.dom.Element after = XMLUtil.getLastChild(telecom, "id", "extension", "system");
// if (after != null) {
// after = XMLUtil.getNextSibling(after);
// }
// telecom.insertBefore(system, after);
// telecom.insertBefore(res.getOwnerDocument().createTextNode("\n "), after);
// }
// value.setAttribute("value", wg.getLink());
// }
// }
}

View File

@ -137,4 +137,7 @@ public class NamedItemList<T extends org.hl7.fhir.utilities.NamedItemList.NamedI
Collections.sort(list, sorter);
}
public void clearMap() {
map = null;
}
}

View File

@ -2,6 +2,7 @@ package org.hl7.fhir.utilities;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.StringJoiner;
@ -650,6 +651,15 @@ public class VersionUtilities {
String mm2 = getMajMin(v2);
return mm1 != null && mm2 != null && mm1.equals(mm2);
}
public static boolean versionsMatch(String v1, List<String> v2l) {
for (String v2 : v2l) {
if (versionsMatch(v1, v2)) {
return true;
}
}
return false;
}
public static boolean isR5VerOrLater(String version) {
if (version == null) {

View File

@ -1085,6 +1085,7 @@ public class I18nConstants {
public static final String IG_DEPENDENCY_CLASH_PACKAGEID = "IG_DEPENDENCY_CLASH_PACKAGEID";
public static final String IG_DEPENDENCY_CLASH_CANONICAL = "IG_DEPENDENCY_CLASH_CANONICAL";
public static final String IG_DEPENDENCY_NO_PACKAGE = "IG_DEPENDENCY_NO_PACKAGE";
public static final String IG_NO_VERSION = "IG_NO_VERSION";
public static final String IG_DEPENDENCY_NO_VERSION = "IG_DEPENDENCY_NO_VERSION";
public static final String IG_DEPENDENCY_INVALID_PACKAGE_VERSION = "IG_DEPENDENCY_INVALID_PACKAGE_VERSION";
public static final String IG_DEPENDENCY_VERSION_ERROR = "IG_DEPENDENCY_VERSION_ERROR";

View File

@ -87,6 +87,7 @@ public class POGenerator {
}
private List<String> prefixes = new ArrayList<>();
private int noTrans = 0;
private void execute(String core, String igpub, String pascal) throws IOException {
String source = Utilities.path(core, "/org.hl7.fhir.utilities/src/main/resources");
@ -409,7 +410,7 @@ public class POGenerator {
if (o.duplicate) {
b.append("msgctxt \""+o.id+"\"\r\n");
}
String m = tfxMode && Utilities.noString(o.msgid) ? "-- no content: do not translate --" : o.msgid;
String m = tfxMode && Utilities.noString(o.msgid) ? "-- no content: do not translate #"+(++noTrans )+" --" : o.msgid;
b.append("msgid \""+wrapQuotes(m)+"\"\r\n");
if (o.msgidPlural != null) {
b.append("msgid_plural \""+wrapQuotes(o.msgidPlural)+"\"\r\n");
@ -417,7 +418,11 @@ public class POGenerator {
o.msgstr.add("");
}
for (int i = 0; i < o.msgstr.size(); i++) {
b.append("msgstr["+i+"] \""+wrapQuotes(o.msgstr.get(i))+"\"\r\n");
String s = o.msgstr.get(i);
// if (tfxMode && Utilities.noString(s)) {
// s = Utilities.noString(i == 0 ? o.msgid : o.msgidPlural) ? "-- no content: do not translate --" : "";
// }
b.append("msgstr["+i+"] \""+wrapQuotes(s)+"\"\r\n");
}
} else {
if (o.msgstr.size() == 0) {

View File

@ -1168,11 +1168,11 @@ public class HierarchicalTableGenerator {
}
public String prefixAnchor(String anchor) {
return uniqueLocalPrefix == null ? anchor : uniqueLocalPrefix+"-" + anchor;
return Utilities.noString(uniqueLocalPrefix) ? anchor : uniqueLocalPrefix+"-" + anchor;
}
public String prefixLocalHref(String url) {
if (url == null || uniqueLocalPrefix == null || !url.startsWith("#")) {
if (url == null || Utilities.noString(uniqueLocalPrefix) || !url.startsWith("#")) {
return url;
}
return "#"+uniqueLocalPrefix+"-"+url.substring(1);

View File

@ -39,6 +39,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.instance.model.api.IBaseXhtml;
@ -1127,4 +1128,15 @@ public class XhtmlNode extends XhtmlFluent implements IBaseXhtml {
default: return 0;
}
}
public void stripAnchorsByName(Set<String> anchors) {
if (hasChildren()) {
childNodes.removeIf(n -> "a".equals(n.getName()) && anchors.contains(n.getAttribute("name")));
for (XhtmlNode c : childNodes) {
c.stripAnchorsByName(anchors);
}
}
}
}

View File

@ -1137,7 +1137,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
timeTracker.tx(t, "vc "+system+"#"+code+" '"+display+"'");
if (s == null)
return true;
ok = processTxIssues(errors, s, element, path, null, false, null) & ok;
ok = processTxIssues(errors, s, element, path, null, "no binding on code", false, null) & ok;
if (s.isOk()) {
if (s.getMessage() != null && !s.messageIsInIssues()) {
@ -1393,7 +1393,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (cc.hasCoding()) {
long t = System.nanoTime();
ValidationResult vr = checkCodeOnServer(stack, null, cc);
bh.see(processTxIssues(errors, vr, element, path, org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION, false, null));
bh.see(processTxIssues(errors, vr, element, path, org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION, null, false, null));
timeTracker.tx(t, "vc " + cc.toString());
}
} catch (CheckCodeOnServerException e) {
@ -1477,7 +1477,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
} else {
checked.set(true);
ValidationResult vr = checkCodeOnServer(stack, valueset, cc);
bh.see(processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(strength), false, vsRef));
bh.see(processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(strength), notFoundSeverityNoteForBinding(strength), false, vsRef));
if (!vr.isOk()) {
bindingsOk = false;
if (vr.getErrorClass() != null && vr.getErrorClass() == TerminologyServiceErrorClass.NOSERVICE) {
@ -1545,6 +1545,14 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
return checkDisp;
}
private String notFoundSeverityNoteForBinding(BindingStrength strength) {
if (strength == BindingStrength.REQUIRED) {
return "error because this is a required binding";
} else {
return null;
}
}
/**
* The terminology server will report an error for an unknown code system or version, or a dependent valueset
*
@ -1563,7 +1571,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
private boolean processTxIssues(List<ValidationMessage> errors, ValidationResult vr, Element element, String path,
org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity notFoundLevel, boolean ignoreCantInfer, String vsurl) {
org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity notFoundLevel, String notFoundNote, boolean ignoreCantInfer, String vsurl) {
boolean ok = true;
if (vr != null) {
for (OperationOutcomeIssueComponent iss : vr.getIssues()) {
@ -1571,9 +1579,12 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
&& !iss.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "this-code-not-in-vs")
&& !(ignoreCantInfer || iss.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "cannot-infer"))) {
OperationOutcomeIssueComponent i = iss.copy();
if (notFoundLevel != null && i.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "not-found")) {
if (i.getSeverity().isHigherThan(notFoundLevel) || (vsurl != null && i.getDetails().getText().contains(vsurl))) {
i.setSeverity(notFoundLevel);
if (i.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "not-found")) {
if (notFoundLevel != null && i.getSeverity().isHigherThan(notFoundLevel) || (vsurl != null && i.getDetails().getText().contains(vsurl))) {
i.setSeverity(notFoundLevel);
}
if (notFoundNote != null) {
i.getDetails().setText(i.getDetails().getText()+" ("+notFoundNote+")");
}
}
if (baseOptions.isDisplayWarningMode() && i.getSeverity() == org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR && i.getDetails().hasCoding("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", "invalid-display")) {
@ -1593,7 +1604,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
boolean ok = true;
if (isNotBlank(nextCoding.getCode()) && isNotBlank(nextCoding.getSystem()) && context.supportsSystem(nextCoding.getSystem(), baseOptions.getFhirVersion())) {
ValidationResult vr = checkCodeOnServer(stack, valueset, nextCoding);
ok = processTxIssues(errors, vr, element, path, null, false, null) && ok;
ok = processTxIssues(errors, vr, element, path, null, "ex-checkBindings", false, null) && ok;
if (vr.getSeverity() != null && !vr.messageIsInIssues()) {
if (vr.getSeverity() == IssueSeverity.INFORMATION) {
@ -1722,7 +1733,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (strength == BindingStrength.REQUIRED) {
removeTrackedMessagesForLocation(errors, element, path);
}
ok = processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(strength), false, vsRef) && ok;
ok = processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(strength), notFoundSeverityNoteForBinding(strength), false, vsRef) && ok;
timeTracker.tx(t, "vc "+system+"#"+code+" '"+display+"'");
if (vr != null && !vr.isOk()) {
if (vr.IsNoService())
@ -1852,7 +1863,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
try {
long t = System.nanoTime();
ValidationResult vr = checkCodeOnServer(stack, valueset, cc);
ok = processTxIssues(errors, vr, element, path, null, false, maxVSUrl) && ok;
ok = processTxIssues(errors, vr, element, path, null, "ex-checkMaxValueSet", false, maxVSUrl) && ok;
timeTracker.tx(t, "vc "+cc.toString());
if (!vr.isOk()) {
if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure())
@ -1891,7 +1902,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
try {
long t = System.nanoTime();
ValidationResult vr = checkCodeOnServer(stack, valueset, c);
ok = processTxIssues(errors, vr, element, path, null, false, maxVSUrl) && ok;
ok = processTxIssues(errors, vr, element, path, null, "ex-checkMaxValueSet-2", false, maxVSUrl) && ok;
timeTracker.tx(t, "vc "+c.getSystem()+"#"+c.getCode()+" '"+c.getDisplay()+"'");
if (!vr.isOk()) {
@ -1922,7 +1933,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
try {
long t = System.nanoTime();
ValidationResult vr = checkCodeOnServer(stack, valueset, value, baseOptions.withLanguage(stack.getWorkingLang()));
ok = processTxIssues(errors, vr, element, path, null, false, maxVSUrl) && ok;
ok = processTxIssues(errors, vr, element, path, null, "ex-checkMaxValueSet-3", false, maxVSUrl) && ok;
timeTracker.tx(t, "vc "+value);
if (!vr.isOk()) {
if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure())
@ -2046,7 +2057,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
checked.set(true);
vr = checkCodeOnServer(stack, valueset, c);
}
ok = processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(strength), strength == BindingStrength.EXTENSIBLE, vsRef) && ok;
ok = processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(strength), notFoundSeverityNoteForBinding(strength), strength == BindingStrength.EXTENSIBLE, vsRef) && ok;
timeTracker.tx(t, "vc "+c.getSystem()+"#"+c.getCode()+" '"+c.getDisplay()+"'");
if (strength == BindingStrength.REQUIRED) {
@ -3482,7 +3493,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
vr = checkCodeOnServer(stack, vs, value, options);
}
ok = processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(binding.getStrength()), binding.getStrength() != BindingStrength.REQUIRED, binding.getValueSet()) && ok;
ok = processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(binding.getStrength()), notFoundSeverityNoteForBinding(binding.getStrength()), binding.getStrength() != BindingStrength.REQUIRED, binding.getValueSet()) && ok;
timeTracker.tx(t, "vc "+value+"");
if (binding.getStrength() == BindingStrength.REQUIRED) {
@ -4608,7 +4619,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
String fullUrl = null; // we're going to try to work this out as we go up
while (focus != null) {
// track the stack while we can
if (focus.getSpecial() == SpecialElement.BUNDLE_ENTRY && fullUrl == null && focus != null && focus.getParentForValidator().getName().equals(ENTRY)) {
if (focus.getSpecial() == SpecialElement.BUNDLE_ENTRY && fullUrl == null && focus != null && focus.getParentForValidator() != null && focus.getParentForValidator().getName().equals(ENTRY)) {
String type = focus.getParentForValidator().getChildValue(TYPE);
fullUrl = focus.getParentForValidator().getChildValue(FULL_URL); // we don't try to resolve contained references across this boundary
if (fullUrl == null)

View File

@ -59,18 +59,24 @@ public class ImplementationGuideValidator extends BaseValidator {
public boolean validateImplementationGuide(ValidationContext valContext, List<ValidationMessage> errors, Element ig, NodeStack stack) {
boolean ok = true;
String fver = ig.getNamedChildValue("fhirVersion");
List<Element> el = ig.getChildren("fhirVersion");
List<String> fvl = new ArrayList<String>();
for (Element e : el) {
String fver = e.primitiveValue();
fvl.add(fver);
}
warning(errors, "2024-06-13", IssueType.BUSINESSRULE, ig.line(), ig.col(), stack.getLiteralPath(), !fvl.isEmpty(), I18nConstants.IG_NO_VERSION);
List<Element> dependencies = ig.getChildrenByName("dependsOn");
int i = 0;
for (Element dependency : dependencies) {
ok = checkDependency(errors, ig, stack.push(dependency, i, null, null), dependency, fver) && ok;
ok = checkDependency(errors, ig, stack.push(dependency, i, null, null), dependency, fvl) && ok;
i++;
}
return ok;
}
private boolean checkDependency(List<ValidationMessage> errors, Element ig, NodeStack stack, Element dependency, String fver) {
private boolean checkDependency(List<ValidationMessage> errors, Element ig, NodeStack stack, Element dependency, List<String> fvl) {
boolean ok = true;
String url = dependency.getNamedChildValue("url");
String packageId = dependency.getNamedChildValue("packageId");
@ -95,13 +101,15 @@ public class ImplementationGuideValidator extends BaseValidator {
ok = rule(errors, "2024-06-13", IssueType.BUSINESSRULE, dependency.line(), dependency.col(), stack.getLiteralPath(), (packageId+"#"+version).matches(FilesystemPackageCacheManager.PACKAGE_VERSION_REGEX), I18nConstants.IG_DEPENDENCY_INVALID_PACKAGE_VERSION, version) && ok;
NpmPackage npm = pcm.loadPackage(packageId, version);
if (warning(errors, "2024-06-13", IssueType.BUSINESSRULE, dependency.line(), dependency.col(), stack.getLiteralPath(), npm != null, I18nConstants.IG_DEPENDENCY_PACKAGE_UNKNOWN, packageId+"#"+version)) {
String pver = npm.fhirVersion();
if (!VersionUtilities.versionsMatch(pver, fver)) {
if ("hl7.fhir.uv.extensions".equals(packageId)) {
ok = rule(errors, "2024-06-13", IssueType.BUSINESSRULE, dependency.line(), dependency.col(), stack.getLiteralPath(), false, I18nConstants.IG_DEPENDENCY_VERSION_ERROR, fver, packageId+"#"+version, pver,
"hl7.fhir.uv.extensions."+VersionUtilities.getNameForVersion(fver).toLowerCase()) && ok;
} else {
warning(errors, "2024-06-13", IssueType.BUSINESSRULE, dependency.line(), dependency.col(), stack.getLiteralPath(), false, I18nConstants.IG_DEPENDENCY_VERSION_WARNING, fver, packageId+"#"+version, pver);
if (fvl.isEmpty()) {
String pver = npm.fhirVersion();
if (!VersionUtilities.versionsMatch(pver, fvl)) {
if ("hl7.fhir.uv.extensions".equals(packageId)) {
ok = rule(errors, "2024-06-13", IssueType.BUSINESSRULE, dependency.line(), dependency.col(), stack.getLiteralPath(), false, I18nConstants.IG_DEPENDENCY_VERSION_ERROR, CommaSeparatedStringBuilder.join(",", fvl), packageId+"#"+version, pver,
"hl7.fhir.uv.extensions."+VersionUtilities.getNameForVersion(fvl.get(0)).toLowerCase()) && ok;
} else {
warning(errors, "2024-06-13", IssueType.BUSINESSRULE, dependency.line(), dependency.col(), stack.getLiteralPath(), false, I18nConstants.IG_DEPENDENCY_VERSION_WARNING, CommaSeparatedStringBuilder.join(",", fvl), packageId+"#"+version, pver);
}
}
}
}

View File

@ -3547,7 +3547,6 @@ v: {
"code" : "image/png",
"system" : "urn:ietf:bcp:13",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -3568,6 +3567,26 @@ v: {
"code" : "image/png",
"system" : "urn:ietf:bcp:13",
"server" : "http://tx-dev.fhir.org/r4",
"issues" : {
"resourceType" : "OperationOutcome"
}
}
-------------------------------------------------------------------------------------
{"code" : {
"code" : "en-AU"
}, "url": "http://hl7.org/fhir/ValueSet/languages", "version": "4.0.1", "langs":"en-AU", "useServer":"true", "useClient":"true", "guessSystem":"true", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"true", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"display" : "English (Australia)",
"code" : "en-AU",
"system" : "urn:ietf:bcp:47",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"

View File

@ -7522,6 +7522,29 @@ v: {
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"issues" : {
"resourceType" : "OperationOutcome"
}
}
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://loinc.org",
"code" : "3150-0",
"display" : "Inhaled oxygen concentration"
}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"false", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"display" : "Inhaled oxygen concentration",
"code" : "3150-0",
"system" : "http://loinc.org",
"version" : "2.77",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"

View File

@ -511,6 +511,23 @@ v: {
"location" : ["CodeableConcept.coding[0].code"],
"expression" : ["CodeableConcept.coding[0].code"]
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-server",
"valueUrl" : "http://tx-dev.fhir.org/r4"
}],
"severity" : "information",
"code" : "invalid",
"details" : {
"coding" : [{
"system" : "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
"code" : "code-rule"
}],
"text" : "The code '1419004' is valid but is not active"
},
"location" : ["CodeableConcept.coding[0].code"],
"expression" : ["CodeableConcept.coding[0].code"]
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-server",
@ -867,6 +884,23 @@ v: {
"location" : ["CodeableConcept.coding[0].code"],
"expression" : ["CodeableConcept.coding[0].code"]
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-server",
"valueUrl" : "http://tx-dev.fhir.org/r4"
}],
"severity" : "information",
"code" : "invalid",
"details" : {
"coding" : [{
"system" : "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
"code" : "code-rule"
}],
"text" : "The code '324252006' is valid but is not active"
},
"location" : ["CodeableConcept.coding[0].code"],
"expression" : ["CodeableConcept.coding[0].code"]
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-server",
@ -1126,6 +1160,23 @@ v: {
"location" : ["CodeableConcept.coding[0].code"],
"expression" : ["CodeableConcept.coding[0].code"]
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-server",
"valueUrl" : "http://tx-dev.fhir.org/r4"
}],
"severity" : "information",
"code" : "invalid",
"details" : {
"coding" : [{
"system" : "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
"code" : "code-rule"
}],
"text" : "The code '602001' is valid but is not active"
},
"location" : ["CodeableConcept.coding[0].code"],
"expression" : ["CodeableConcept.coding[0].code"]
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-server",
@ -1707,6 +1758,23 @@ v: {
"location" : ["CodeableConcept.coding[0].code"],
"expression" : ["CodeableConcept.coding[0].code"]
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-server",
"valueUrl" : "http://tx-dev.fhir.org/r4"
}],
"severity" : "information",
"code" : "invalid",
"details" : {
"coding" : [{
"system" : "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
"code" : "code-rule"
}],
"text" : "The code '1419004' is valid but is not active"
},
"location" : ["CodeableConcept.coding[0].code"],
"expression" : ["CodeableConcept.coding[0].code"]
},
{
"extension" : [{
"url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-server",
@ -8395,7 +8463,6 @@ v: {
"system" : "http://snomed.info/sct",
"version" : "http://snomed.info/sct/900000000000207008/version/20240201",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -8418,6 +8485,77 @@ v: {
"system" : "http://snomed.info/sct",
"version" : "http://snomed.info/sct/900000000000207008/version/20240201",
"server" : "http://tx-dev.fhir.org/r4",
"issues" : {
"resourceType" : "OperationOutcome"
}
}
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://snomed.info/sct",
"code" : "442476006",
"display" : "Arterial oxygen saturation"
}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"false", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"display" : "Arterial oxygen saturation",
"code" : "442476006",
"system" : "http://snomed.info/sct",
"version" : "http://snomed.info/sct/900000000000207008/version/20240201",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
}
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://snomed.info/sct",
"code" : "427081008",
"display" : "Delivered oxygen flow rate"
}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"false", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"display" : "Delivered oxygen flow rate (observable entity)",
"code" : "427081008",
"system" : "http://snomed.info/sct",
"version" : "http://snomed.info/sct/900000000000207008/version/20240201",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
}
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://snomed.info/sct",
"code" : "250774007",
"display" : "Inspired oxygen concentration"
}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"false", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"display" : "Inspired oxygen concentration",
"code" : "250774007",
"system" : "http://snomed.info/sct",
"version" : "http://snomed.info/sct/900000000000207008/version/20240201",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"

View File

@ -1272,7 +1272,6 @@ v: {
"system" : "http://unitsofmeasure.org",
"version" : "2.0.1",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -1295,7 +1294,6 @@ v: {
"system" : "http://unitsofmeasure.org",
"version" : "2.0.1",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -1318,7 +1316,6 @@ v: {
"system" : "http://unitsofmeasure.org",
"version" : "2.0.1",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -1341,7 +1338,6 @@ v: {
"system" : "http://unitsofmeasure.org",
"version" : "2.0.1",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -1364,7 +1360,6 @@ v: {
"system" : "http://unitsofmeasure.org",
"version" : "2.0.1",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -1387,7 +1382,6 @@ v: {
"system" : "http://unitsofmeasure.org",
"version" : "2.0.1",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -1410,7 +1404,6 @@ v: {
"system" : "http://unitsofmeasure.org",
"version" : "2.0.1",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"
}
@ -1433,6 +1426,28 @@ v: {
"system" : "http://unitsofmeasure.org",
"version" : "2.0.1",
"server" : "http://tx-dev.fhir.org/r4",
"issues" : {
"resourceType" : "OperationOutcome"
}
}
-------------------------------------------------------------------------------------
{"code" : {
"system" : "http://unitsofmeasure.org",
"code" : "%"
}, "url": "http://hl7.org/fhir/test/ValueSet/UcumVitalsCommonDE", "version": "1.5.0", "langs":"", "useServer":"true", "useClient":"true", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
"resourceType" : "Parameters",
"parameter" : [{
"name" : "profile-url",
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
}]
}}####
v: {
"display" : "%",
"code" : "%",
"system" : "http://unitsofmeasure.org",
"version" : "2.0.1",
"server" : "http://tx-dev.fhir.org/r4",
"unknown-systems" : "",
"issues" : {
"resourceType" : "OperationOutcome"