Merge remote-tracking branch 'origin/master' into do-20240122-base-engine

This commit is contained in:
dotasek 2024-06-07 16:00:17 -04:00
commit b24fb10f54
32 changed files with 473 additions and 324 deletions

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.11-SNAPSHOT</version> <version>6.3.12-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.11-SNAPSHOT</version> <version>6.3.12-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.11-SNAPSHOT</version> <version>6.3.12-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.11-SNAPSHOT</version> <version>6.3.12-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -1657,7 +1657,7 @@ public class ProfileUtilities extends TranslatingUtilities {
r.getCells().add(gen.new Cell("", "", "Extension", null, null)); r.getCells().add(gen.new Cell("", "", "Extension", null, null));
r.setIcon("icon_"+m+"extension_complex.png", HierarchicalTableGenerator.TEXT_ICON_EXTENSION_COMPLEX); r.setIcon("icon_"+m+"extension_complex.png", HierarchicalTableGenerator.TEXT_ICON_EXTENSION_COMPLEX);
for (ElementDefinition c : children) { for (ElementDefinition c : children) {
ved = getValueFor(ed, c); ved = getValueFor(ed, c);
ElementDefinition ued = getUrlFor(ed, c); ElementDefinition ued = getUrlFor(ed, c);
@ -1697,7 +1697,7 @@ public class ProfileUtilities extends TranslatingUtilities {
} }
c.addPiece(gen.new Piece("br")).addPiece(gen.new Piece(null, describeExtensionContext(ed), null)); c.addPiece(gen.new Piece("br")).addPiece(gen.new Piece(null, describeExtensionContext(ed), null));
r.getCells().add(c); r.getCells().add(c);
try { try {
return gen.generate(model, corePath, 0, outputTracker); return gen.generate(model, corePath, 0, outputTracker);
} catch (org.hl7.fhir.exceptions.FHIRException e) { } catch (org.hl7.fhir.exceptions.FHIRException e) {
@ -3484,7 +3484,7 @@ public class ProfileUtilities extends TranslatingUtilities {
TableModel model = initSpanningTable(gen, "", false, profile.getId()); TableModel model = initSpanningTable(gen, "", false, profile.getId());
Set<String> processed = new HashSet<String>(); Set<String> processed = new HashSet<String>();
SpanEntry span = buildSpanningTable("(focus)", "", profile, processed, onlyConstraints, constraintPrefix); SpanEntry span = buildSpanningTable("(focus)", "", profile, processed, onlyConstraints, constraintPrefix);
genSpanEntry(gen, model.getRows(), span); genSpanEntry(gen, model.getRows(), span);
return gen.generate(model, "", 0, outputTracker); return gen.generate(model, "", 0, outputTracker);
} }

View File

@ -1,33 +1,33 @@
package org.hl7.fhir.dstu3.utils; package org.hl7.fhir.dstu3.utils;
/* /*
Copyright (c) 2011+, HL7, Inc. Copyright (c) 2011+, HL7, Inc.
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met: are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this * Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer. list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, * Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution. and/or other materials provided with the distribution.
* Neither the name of HL7 nor the names of its contributors may be used to * Neither the name of HL7 nor the names of its contributors may be used to
endorse or promote products derived from this software without specific endorse or promote products derived from this software without specific
prior written permission. prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. POSSIBILITY OF SUCH DAMAGE.
*/ */
@ -3236,7 +3236,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
case INEXACT : return "><"; case INEXACT : return "><";
case UNMATCHED : return "-"; case UNMATCHED : return "-";
case DISJOINT : return "!="; case DISJOINT : return "!=";
case NULL: return null; case NULL: return null;
default: return "?"; default: return "?";
} }
} }
@ -3708,6 +3708,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
inject(sd, x, NarrativeStatus.GENERATED); inject(sd, x, NarrativeStatus.GENERATED);
return true; return true;
} }
public boolean generate(ResourceContext rcontext, ImplementationGuide ig) throws EOperationOutcome, FHIRException, IOException { public boolean generate(ResourceContext rcontext, ImplementationGuide ig) throws EOperationOutcome, FHIRException, IOException {
XhtmlNode x = new XhtmlNode(NodeType.Element, "div"); XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
x.h2().addText(ig.getName()); x.h2().addText(ig.getName());

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.11-SNAPSHOT</version> <version>6.3.12-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.11-SNAPSHOT</version> <version>6.3.12-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.11-SNAPSHOT</version> <version>6.3.12-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -1253,7 +1253,7 @@ public class StructureDefinitionComparer extends CanonicalResourceComparer imple
public XhtmlNode renderStructure(ProfileComparison comp, String id, String prefix, String corePath) throws FHIRException, IOException { public XhtmlNode renderStructure(ProfileComparison comp, String id, String prefix, String corePath) throws FHIRException, IOException {
HierarchicalTableGenerator gen = new HierarchicalTableGenerator(session.getI18n(), Utilities.path("[tmp]", "compare"), false, true); HierarchicalTableGenerator gen = new HierarchicalTableGenerator(session.getI18n(), Utilities.path("[tmp]", "compare"), false, true);
TableModel model = gen.initComparisonTable(corePath, id); TableModel model = gen.initComparisonTable(corePath, id);
genElementComp(null /* come back to this later */, gen, model.getRows(), comp.combined, corePath, prefix, null, true); genElementComp(null /* come back to this later */, null /* come back to this later */, gen, model.getRows(), comp.combined, corePath, prefix, null, true);
return gen.generate(model, prefix, 0, null); return gen.generate(model, prefix, 0, null);
} }
@ -1268,7 +1268,7 @@ public class StructureDefinitionComparer extends CanonicalResourceComparer imple
return sdr.generateTable(corePath, comp.intersection, false, prefix, false, id, true, corePath, prefix, false, true, null, false, sdr.getContext(), "i"); return sdr.generateTable(corePath, comp.intersection, false, prefix, false, id, true, corePath, prefix, false, true, null, false, sdr.getContext(), "i");
} }
private void genElementComp(String defPath, HierarchicalTableGenerator gen, List<Row> rows, StructuralMatch<ElementDefinitionNode> combined, String corePath, String prefix, Row slicingRow, boolean root) throws IOException { private void genElementComp(String defPath, String anchorPrefix, HierarchicalTableGenerator gen, List<Row> rows, StructuralMatch<ElementDefinitionNode> combined, String corePath, String prefix, Row slicingRow, boolean root) throws IOException {
Row originalRow = slicingRow; Row originalRow = slicingRow;
Row typesRow = null; Row typesRow = null;
@ -1334,19 +1334,19 @@ public class StructureDefinitionComparer extends CanonicalResourceComparer imple
nc = sdrRight.genElementNameCell(gen, combined.getRight().getDef(), "??", true, corePath, prefix, root, false, false, combined.getRight().getSrc(), typesRow, row, false, ext, used , ref, sName, null); nc = sdrRight.genElementNameCell(gen, combined.getRight().getDef(), "??", true, corePath, prefix, root, false, false, combined.getRight().getSrc(), typesRow, row, false, ext, used , ref, sName, null);
} }
if (combined.hasLeft()) { if (combined.hasLeft()) {
frame(sdrLeft.genElementCells(gen, combined.getLeft().getDef(), "??", true, corePath, prefix, root, false, false, combined.getLeft().getSrc(), typesRow, row, true, ext, used , ref, sName, nc, false, false, sdrLeft.getContext(), children.size() > 0), leftColor); frame(sdrLeft.genElementCells(gen, combined.getLeft().getDef(), "??", true, corePath, prefix, root, false, false, combined.getLeft().getSrc(), typesRow, row, true, ext, used , ref, sName, nc, false, false, sdrLeft.getContext(), children.size() > 0, defPath, anchorPrefix, new ArrayList<ElementDefinition>()), leftColor);
} else { } else {
frame(spacers(row, 4, gen), leftColor); frame(spacers(row, 4, gen), leftColor);
} }
if (combined.hasRight()) { if (combined.hasRight()) {
frame(sdrRight.genElementCells(gen, combined.getRight().getDef(), "??", true, corePath, prefix, root, false, false, combined.getRight().getSrc(), typesRow, row, true, ext, used, ref, sName, nc, false, false, sdrRight.getContext(), children.size() > 0), rightColor); frame(sdrRight.genElementCells(gen, combined.getRight().getDef(), "??", true, corePath, prefix, root, false, false, combined.getRight().getSrc(), typesRow, row, true, ext, used, ref, sName, nc, false, false, sdrRight.getContext(), children.size() > 0, defPath, anchorPrefix, new ArrayList<ElementDefinition>()), rightColor);
} else { } else {
frame(spacers(row, 4, gen), rightColor); frame(spacers(row, 4, gen), rightColor);
} }
row.getCells().add(cellForMessages(gen, combined.getMessages())); row.getCells().add(cellForMessages(gen, combined.getMessages()));
for (StructuralMatch<ElementDefinitionNode> child : children) { for (StructuralMatch<ElementDefinitionNode> child : children) {
genElementComp(defPath, gen, row.getSubRows(), child, corePath, prefix, originalRow, false); genElementComp(defPath, anchorPrefix, gen, row.getSubRows(), child, corePath, prefix, originalRow, false);
} }
} }

View File

@ -611,18 +611,24 @@ public class Element extends Base implements NamedItem {
} }
@Override @Override
public boolean hasPrimitiveValue() { public boolean hasPrimitiveValue() {
return property.isPrimitiveName(name) || property.IsLogicalAndHasPrimitiveValue(name); //return property.isPrimitiveName(name) || property.IsLogicalAndHasPrimitiveValue(name);
} return super.hasPrimitiveValue();
}
@Override
public boolean canHavePrimitiveValue() {
return property.isPrimitiveName(name) || property.IsLogicalAndHasPrimitiveValue(name);
}
@Override @Override
public String primitiveValue() { public String primitiveValue() {
if (isPrimitive() || value != null) if (isPrimitive() || value != null)
return value; return value;
else { else {
if (hasPrimitiveValue() && children != null) { if (canHavePrimitiveValue() && children != null) {
for (Element c : children) { for (Element c : children) {
if (c.getName().equals("value")) if (c.getName().equals("value"))
return c.primitiveValue(); return c.primitiveValue();

View File

@ -258,32 +258,70 @@ public abstract class Base implements Serializable, IBase, IElement {
} }
// these 3 allow evaluation engines to get access to primitive values // these 3 allow evaluation engines to get access to primitive values
/**
* @return true if the data type is a primitive type and might have a primitive value
* (which will be accessed as a string, irrespective of the stated value)
*/
public boolean isPrimitive() { public boolean isPrimitive() {
return false; return false;
} }
/**
* @return true if the type is boolean, and the primitive value can only be 'true' or 'false'
*/
public boolean isBooleanPrimitive() { public boolean isBooleanPrimitive() {
return false; return false;
} }
public boolean hasPrimitiveValue() { /**
return isPrimitive(); * @return true if the type is primitive, and there's value (e.g. no Data-Absent-Reason extension etc)
} */
public boolean hasPrimitiveValue() {
return primitiveValue() != null;
}
/**
* @return true if the type is primitive, and there could be a value (irrespective of whether it's present e.g. no Data-Absent-Reason extension etc)
*/
public boolean canHavePrimitiveValue() {
return false;
}
/**
* @return the primitive value if there is one, as a string irrespective of the actual type (e.g. dates converted to their FHIR string representation)
* return null if the value is not a primitive or there is no value (might be extensions instead)
*/
public String primitiveValue() { public String primitiveValue() {
return null; return null;
} }
/**
* @return true if the type is date|dateTime|instant, and the primitive value is a date/time of some precision
*/
public boolean isDateTime() { public boolean isDateTime() {
return false; return false;
} }
/**
* @return the date/time value if there is one, or null
*/
public BaseDateTimeType dateTimeValue() { public BaseDateTimeType dateTimeValue() {
return null; return null;
} }
/**
* @return the FHIR type name of the instance (not the java class name)
*/
public abstract String fhirType() ; public abstract String fhirType() ;
/**
* Note that this is potentially misleading on ElementDefinition that has a 'type'
* property - don't mistakenly use this thinking it's going to look at ElementDefinition.type
*
* @param name - fhir type name
* @return- true if it 'has' this type (including by specialization)
*/
public boolean hasType(String... name) { public boolean hasType(String... name) {
String t = fhirType(); String t = fhirType();
for (String n : name) { for (String n : name) {

View File

@ -257,6 +257,11 @@ public abstract class PrimitiveType<T> extends DataType implements IPrimitiveTyp
public boolean hasPrimitiveValue() { public boolean hasPrimitiveValue() {
return StringUtils.isNotBlank(getValueAsString()); return StringUtils.isNotBlank(getValueAsString());
} }
public boolean canHavePrimitiveValue() {
return true;
}
public String fpValue() { public String fpValue() {
return primitiveValue(); return primitiveValue();

View File

@ -6,6 +6,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import org.fhir.ucum.Canonical;
import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRFormatError; import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.conformance.profile.BindingResolution; import org.hl7.fhir.r5.conformance.profile.BindingResolution;
@ -14,6 +15,7 @@ import org.hl7.fhir.r5.conformance.profile.ProfileUtilities;
import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingAdditionalComponent; import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingAdditionalComponent;
import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent; import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent;
import org.hl7.fhir.r5.model.ActorDefinition; import org.hl7.fhir.r5.model.ActorDefinition;
import org.hl7.fhir.r5.model.CanonicalType;
import org.hl7.fhir.r5.model.CodeSystem; import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.Coding; import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.ElementDefinition;
@ -40,9 +42,9 @@ import org.hl7.fhir.utilities.xhtml.XhtmlNodeList;
public class ObligationsRenderer { public class ObligationsRenderer {
public static class ObligationDetail { public static class ObligationDetail {
private String code; private List<String> codes = new ArrayList<>();
private List<String> elementIds = new ArrayList<>(); private List<String> elementIds = new ArrayList<>();
private String actor; private List<CanonicalType> actors = new ArrayList<>();
private String doco; private String doco;
private String docoShort; private String docoShort;
private String filter; private String filter;
@ -57,10 +59,11 @@ public class ObligationsRenderer {
private int count = 1; private int count = 1;
public ObligationDetail(Extension ext) { public ObligationDetail(Extension ext) {
this.code = ext.getExtensionString("code"); for (Extension e: ext.getExtensionsByUrl("code")) {
this.actor = ext.getExtensionString("actor"); codes.add(e.getValueStringType().toString());
if (this.actor == null) { }
this.actor = ext.getExtensionString("actorId"); for (Extension e: ext.getExtensionsByUrl("actor")) {
actors.add(e.getValueCanonicalType());
} }
this.doco = ext.getExtensionString("documentation"); this.doco = ext.getExtensionString("documentation");
this.docoShort = ext.getExtensionString("shortDoco"); this.docoShort = ext.getExtensionString("shortDoco");
@ -80,7 +83,7 @@ public class ObligationsRenderer {
private String getKey() { private String getKey() {
// Todo: Consider extending this with content from usageContext if purpose isn't sufficiently differentiating // Todo: Consider extending this with content from usageContext if purpose isn't sufficiently differentiating
return code + Integer.toString(count); return String.join(",", codes) + Integer.toString(count);
} }
private void incrementCount() { private void incrementCount() {
@ -96,8 +99,11 @@ public class ObligationsRenderer {
public String getDoco(boolean full) { public String getDoco(boolean full) {
return full ? doco : docoShort; return full ? doco : docoShort;
} }
public String getCode() { public String getCodes() {
return code; return String.join(",", codes);
}
public List<String> getCodeList() {
return new ArrayList<String>(codes);
} }
public boolean unchanged() { public boolean unchanged() {
if (!isUnchanged) if (!isUnchanged)
@ -105,9 +111,9 @@ public class ObligationsRenderer {
if (compare==null) if (compare==null)
return true; return true;
isUnchanged = true; isUnchanged = true;
isUnchanged = isUnchanged && ((code==null && compare.code==null) || code.equals(compare.code)); isUnchanged = isUnchanged && ((codes.isEmpty() && compare.codes.isEmpty()) || codes.equals(compare.codes));
isUnchanged = elementIds.equals(compare.elementIds); isUnchanged = elementIds.equals(compare.elementIds);
isUnchanged = isUnchanged && ((actor==null && compare.actor==null) || actor.equals(compare.actor)); isUnchanged = isUnchanged && ((actors.isEmpty() && compare.actors.isEmpty()) || actors.equals(compare.actors));
isUnchanged = isUnchanged && ((doco==null && compare.doco==null) || doco.equals(compare.doco)); isUnchanged = isUnchanged && ((doco==null && compare.doco==null) || doco.equals(compare.doco));
isUnchanged = isUnchanged && ((docoShort==null && compare.docoShort==null) || docoShort.equals(compare.docoShort)); isUnchanged = isUnchanged && ((docoShort==null && compare.docoShort==null) || docoShort.equals(compare.docoShort));
isUnchanged = isUnchanged && ((filter==null && compare.filter==null) || filter.equals(compare.filter)); isUnchanged = isUnchanged && ((filter==null && compare.filter==null) || filter.equals(compare.filter));
@ -136,12 +142,16 @@ public class ObligationsRenderer {
return usage; return usage;
} }
public boolean hasActor() { public boolean hasActors() {
return actor != null; return !actors.isEmpty();
} }
public boolean hasActor(String id) { public boolean hasActor(String id) {
return id.equals(actor); for (CanonicalType actor: actors) {
if (actor.getValue().equals(id))
return true;
}
return false;
} }
} }
@ -276,24 +286,24 @@ public class ObligationsRenderer {
return abr; return abr;
} }
public String render() throws IOException { public String render(String defPath, String anchorPrefix, List<ElementDefinition> inScopeElements) throws IOException {
if (obligations.isEmpty()) { if (obligations.isEmpty()) {
return ""; return "";
} else { } else {
XhtmlNode tbl = new XhtmlNode(NodeType.Element, "table"); XhtmlNode tbl = new XhtmlNode(NodeType.Element, "table");
tbl.attribute("class", "grid"); tbl.attribute("class", "grid");
renderTable(tbl.getChildNodes(), true); renderTable(tbl.getChildNodes(), true, defPath, anchorPrefix, inScopeElements);
return new XhtmlComposer(false).compose(tbl); return new XhtmlComposer(false).compose(tbl);
} }
} }
public void renderTable(HierarchicalTableGenerator gen, Cell c) throws FHIRFormatError, DefinitionException, IOException { public void renderTable(HierarchicalTableGenerator gen, Cell c, List<ElementDefinition> inScopeElements) throws FHIRFormatError, DefinitionException, IOException {
if (obligations.isEmpty()) { if (obligations.isEmpty()) {
return; return;
} else { } else {
Piece piece = gen.new Piece("table").attr("class", "grid"); Piece piece = gen.new Piece("table").attr("class", "grid");
c.getPieces().add(piece); c.getPieces().add(piece);
renderTable(piece.getChildren(), false); renderTable(piece.getChildren(), false, gen.getDefPath(), gen.getAnchorPrefix(), inScopeElements);
} }
} }
@ -313,10 +323,21 @@ public class ObligationsRenderer {
} }
private void renderObligationLI(XhtmlNodeList children, ObligationDetail ob) throws IOException { private void renderObligationLI(XhtmlNodeList children, ObligationDetail ob) throws IOException {
renderCode(children, ob.getCode()); renderCodes(children, ob.getCodeList());
if (ob.hasFilter() || ob.hasUsage()) { if (ob.hasFilter() || ob.hasUsage() || !ob.elementIds.isEmpty()) {
children.tx(" ("); children.tx(" (");
boolean ffirst = !ob.hasFilter(); boolean ffirst = !ob.hasFilter();
boolean firstEid = true;
for (String eid: ob.elementIds) {
if (firstEid) {
children.span().i().tx("Elements: ");
firstEid = false;
} else
children.tx(", ");
String trimmedElement = eid.substring(eid.indexOf(".")+ 1);
children.tx(trimmedElement);
}
if (ob.hasFilter()) { if (ob.hasFilter()) {
children.span(null, ob.getFilterDesc()).code().tx(ob.getFilter()); children.span(null, ob.getFilterDesc()).code().tx(ob.getFilter());
} }
@ -337,20 +358,25 @@ public class ObligationsRenderer {
} }
public void renderTable(List<XhtmlNode> children, boolean fullDoco) throws FHIRFormatError, DefinitionException, IOException { public void renderTable(List<XhtmlNode> children, boolean fullDoco, String defPath, String anchorPrefix, List<ElementDefinition> inScopeElements) throws FHIRFormatError, DefinitionException, IOException {
boolean doco = false; boolean doco = false;
boolean usage = false; boolean usage = false;
boolean actor = false; boolean actor = false;
boolean filter = false; boolean filter = false;
boolean elementId = false; boolean elementId = false;
for (ObligationDetail binding : obligations) { for (ObligationDetail binding : obligations) {
actor = actor || binding.actor!=null || (binding.compare!=null && binding.compare.actor !=null); actor = actor || !binding.actors.isEmpty() || (binding.compare!=null && !binding.compare.actors.isEmpty());
doco = doco || binding.getDoco(fullDoco)!=null || (binding.compare!=null && binding.compare.getDoco(fullDoco)!=null); doco = doco || binding.getDoco(fullDoco)!=null || (binding.compare!=null && binding.compare.getDoco(fullDoco)!=null);
usage = usage || !binding.usage.isEmpty() || (binding.compare!=null && !binding.compare.usage.isEmpty()); usage = usage || !binding.usage.isEmpty() || (binding.compare!=null && !binding.compare.usage.isEmpty());
filter = filter || binding.filter != null || (binding.compare!=null && binding.compare.filter!=null); filter = filter || binding.filter != null || (binding.compare!=null && binding.compare.filter!=null);
elementId = elementId || !binding.elementIds.isEmpty() || (binding.compare!=null && !binding.compare.elementIds.isEmpty()); elementId = elementId || !binding.elementIds.isEmpty() || (binding.compare!=null && !binding.compare.elementIds.isEmpty());
} }
List<String> inScopePaths = new ArrayList<>();
for (ElementDefinition e: inScopeElements) {
inScopePaths.add(e.getPath());
}
XhtmlNode tr = new XhtmlNode(NodeType.Element, "tr"); XhtmlNode tr = new XhtmlNode(NodeType.Element, "tr");
children.add(tr); children.add(tr);
tr.td().style("font-size: 11px").b().tx(context.formatPhrase(RenderingContext.GENERAL_OBLIG)); tr.td().style("font-size: 11px").b().tx(context.formatPhrase(RenderingContext.GENERAL_OBLIG));
@ -379,43 +405,52 @@ public class ObligationsRenderer {
children.add(tr); children.add(tr);
XhtmlNode code = tr.td().style("font-size: 11px"); XhtmlNode code = tr.td().style("font-size: 11px");
if (ob.compare!=null && ob.code.equals(ob.compare.code)) if (ob.compare!=null && ob.getCodes().equals(ob.compare.getCodes()))
code.style("font-color: darkgray"); code.style("font-color: darkgray");
renderCode(code.getChildNodes(), ob.code); renderCodes(code.getChildNodes(), ob.getCodeList());
if (ob.compare!=null && ob.compare.code != null && !ob.code.equals(ob.compare.code)) { if (ob.compare!=null && !ob.compare.getCodeList().isEmpty() && !ob.getCodes().equals(ob.compare.getCodes())) {
code.br(); code.br();
code = code.span(STYLE_UNCHANGED, null); code = code.span(STYLE_UNCHANGED, null);
renderCode(code.getChildNodes(), ob.compare.code); renderCodes(code.getChildNodes(), ob.compare.getCodeList());
} }
if (actor) {
ActorDefinition ad = context.getContext().fetchResource(ActorDefinition.class, ob.actor); XhtmlNode actorId = tr.td().style("font-size: 11px");
ActorDefinition compAd = null; if (!ob.actors.isEmpty() || ob.compare.actors.isEmpty()) {
if (ob.compare!=null && ob.compare.actor!=null) { boolean firstActor = false;
compAd = context.getContext().fetchResource(ActorDefinition.class, ob.compare.actor); for (CanonicalType anActor : ob.actors) {
ActorDefinition ad = context.getContext().fetchResource(ActorDefinition.class, anActor.toString());
boolean existingActor = ob.compare != null && ob.compare.actors.contains(anActor);
if (!firstActor) {
actorId.br();
firstActor = true;
}
if (!existingActor)
actorId.style(STYLE_UNCHANGED);
} }
XhtmlNode actorId = tr.td().style("font-size: 11px"); if (ob.compare != null) {
if (ob.compare!=null && ob.actor.equals(ob.compare.actor)) for (CanonicalType compActor : ob.compare.actors) {
actorId.style(STYLE_UNCHANGED); if (!ob.actors.contains(compActor)) {
if (ad != null && ad.hasWebPath()) { ActorDefinition compAd = context.getContext().fetchResource(ActorDefinition.class, compActor.toString());
actorId.ah(ad.getWebPath(), ob.actor).tx(ad.present()); if (!firstActor) {
} else if (ad != null) { actorId.br();
actorId.span(null, ob.actor).tx(ad.present()); firstActor = true;
} }
actorId = actorId.span(STYLE_REMOVED, null);
if (ob.compare!=null && ob.compare.actor!=null && !ob.actor.equals(ob.compare.actor)) { if (compAd.hasWebPath()) {
actorId.br(); actorId.ah(compAd.getWebPath(), compActor.toString()).tx(compAd.present());
actorId = actorId.span(STYLE_REMOVED, null); } else {
if (compAd != null) { actorId.span(null, compActor.toString()).tx(compAd.present());
if (compAd.hasWebPath()) { }
actorId.ah(compAd.getWebPath(), ob.compare.actor).tx(compAd.present());
} else {
actorId.span(null, ob.compare.actor).tx(compAd.present());
} }
} }
} }
} }
if (elementId) { if (elementId) {
XhtmlNode elementIds = tr.td().style("font-size: 11px"); XhtmlNode elementIds = tr.td().style("font-size: 11px");
if (ob.compare!=null && ob.elementIds.equals(ob.compare.elementIds)) if (ob.compare!=null && ob.elementIds.equals(ob.compare.elementIds))
@ -423,10 +458,13 @@ public class ObligationsRenderer {
for (String eid : ob.elementIds) { for (String eid : ob.elementIds) {
elementIds.sep(", "); elementIds.sep(", ");
ElementDefinition ed = profile.getSnapshot().getElementById(eid); ElementDefinition ed = profile.getSnapshot().getElementById(eid);
if (ed != null) { boolean inScope = inScopePaths.contains(ed.getPath());
elementIds.ah("#"+eid).tx(ed.getName()); String name = eid.substring(eid.indexOf(".") + 1);
if (ed != null && inScope) {
String link = defPath + "#" + anchorPrefix + eid;
elementIds.ah(link).tx(name);
} else { } else {
elementIds.code().tx(eid); elementIds.code().tx(name);
} }
} }
@ -491,10 +529,10 @@ public class ObligationsRenderer {
return newS + "<br/><span style=\"" + STYLE_REMOVED + "\">" + oldS + "</span>"; return newS + "<br/><span style=\"" + STYLE_REMOVED + "\">" + oldS + "</span>";
} }
private void renderCode(XhtmlNodeList children, String codeExpr) { private void renderCodes(XhtmlNodeList children, List<String> codes) {
if (codeExpr != null) {
if (!codes.isEmpty()) {
boolean first = true; boolean first = true;
String[] codes = codeExpr.split("\\+");
for (String code : codes) { for (String code : codes) {
if (first) first = false; else children.tx(" & "); if (first) first = false; else children.tx(" & ");
int i = code.indexOf(":"); int i = code.indexOf(":");
@ -507,7 +545,7 @@ public class ObligationsRenderer {
CodeResolution cr = this.cr.resolveCode("http://hl7.org/fhir/tools/CodeSystem/obligation", code); CodeResolution cr = this.cr.resolveCode("http://hl7.org/fhir/tools/CodeSystem/obligation", code);
code = code.replace("will-", "").replace("can-", ""); code = code.replace("will-", "").replace("can-", "");
if (cr.getLink() != null) { if (cr.getLink() != null) {
children.ah(cr.getLink(), cr.getHint()).tx(code); children.ah(cr.getLink(), cr.getHint()).tx(code);
} else { } else {
children.span(null, cr.getHint()).tx(code); children.span(null, cr.getHint()).tx(code);
} }

View File

@ -549,7 +549,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
public XhtmlNode generateTable(String defFile, StructureDefinition profile, boolean diff, String imageFolder, boolean inlineGraphics, String profileBaseFileName, boolean snapshot, String corePath, String imagePath, public XhtmlNode generateTable(String defFile, StructureDefinition profile, boolean diff, String imageFolder, boolean inlineGraphics, String profileBaseFileName, boolean snapshot, String corePath, String imagePath,
boolean logicalModel, boolean allInvariants, Set<String> outputTracker, boolean mustSupport, RenderingContext rc, String anchorPrefix) throws IOException, FHIRException { boolean logicalModel, boolean allInvariants, Set<String> outputTracker, boolean mustSupport, RenderingContext rc, String anchorPrefix) throws IOException, FHIRException {
assert(diff != snapshot);// check it's ok to get rid of one of these assert(diff != snapshot);// check it's ok to get rid of one of these
HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, imageFolder, inlineGraphics, true); HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, imageFolder, inlineGraphics, true, defFile, anchorPrefix);
List<ElementDefinition> list; List<ElementDefinition> list;
if (diff) if (diff)
@ -815,7 +815,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
genElementObligations(gen, element, columns, row, corePath, profile); genElementObligations(gen, element, columns, row, corePath, profile);
break; break;
case SUMMARY: case SUMMARY:
genElementCells(gen, element, profileBaseFileName, snapshot, corePath, imagePath, root, logicalModel, allInvariants, profile, typesRow, row, hasDef, ext, used, ref, sName, nc, mustSupport, true, rc, children.size() > 0); genElementCells(gen, element, profileBaseFileName, snapshot, corePath, imagePath, root, logicalModel, allInvariants, profile, typesRow, row, hasDef, ext, used, ref, sName, nc, mustSupport, true, rc, children.size() > 0, defPath, anchorPrefix, all);
break; break;
} }
if (element.hasSlicing()) { if (element.hasSlicing()) {
@ -1078,7 +1078,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
public List<Cell> genElementCells(HierarchicalTableGenerator gen, ElementDefinition element, String profileBaseFileName, boolean snapshot, String corePath, public List<Cell> genElementCells(HierarchicalTableGenerator gen, ElementDefinition element, String profileBaseFileName, boolean snapshot, String corePath,
String imagePath, boolean root, boolean logicalModel, boolean allInvariants, StructureDefinition profile, Row typesRow, Row row, boolean hasDef, String imagePath, boolean root, boolean logicalModel, boolean allInvariants, StructureDefinition profile, Row typesRow, Row row, boolean hasDef,
boolean ext, UnusedTracker used, String ref, String sName, Cell nameCell, boolean mustSupport, boolean allowSubRows, RenderingContext rc, boolean walksIntoThis) throws IOException { boolean ext, UnusedTracker used, String ref, String sName, Cell nameCell, boolean mustSupport, boolean allowSubRows, RenderingContext rc, boolean walksIntoThis, String defPath, String anchorPrefix, List<ElementDefinition> inScopeElements) throws IOException {
List<Cell> res = new ArrayList<>(); List<Cell> res = new ArrayList<>();
Cell gc = gen.new Cell(); Cell gc = gen.new Cell();
row.getCells().add(gc); row.getCells().add(gc);
@ -1121,7 +1121,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
if (extDefn == null) { if (extDefn == null) {
res.add(genCardinality(gen, element, row, hasDef, used, null)); res.add(genCardinality(gen, element, row, hasDef, used, null));
res.add(addCell(row, gen.new Cell(null, null, "?gen-e1? "+element.getType().get(0).getProfile(), null, null))); res.add(addCell(row, gen.new Cell(null, null, "?gen-e1? "+element.getType().get(0).getProfile(), null, null)));
res.add(generateDescription(gen, row, element, (ElementDefinition) element.getUserData(ProfileUtilities.UD_DERIVATION_POINTER), used.used, profile == null ? "" : profile.getUrl(), eurl, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot, mustSupport, allowSubRows, rc)); res.add(generateDescription(gen, row, element, (ElementDefinition) element.getUserData(ProfileUtilities.UD_DERIVATION_POINTER), used.used, profile == null ? "" : profile.getUrl(), eurl, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot, mustSupport, allowSubRows, rc, inScopeElements));
} else { } else {
String name = element.hasSliceName() ? element.getSliceName() : urltail(eurl); String name = element.hasSliceName() ? element.getSliceName() : urltail(eurl);
nameCell.getPieces().get(0).setText(name); nameCell.getPieces().get(0).setText(name);
@ -1134,7 +1134,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
else // if it's complex, we just call it nothing else // if it's complex, we just call it nothing
// genTypes(gen, row, extDefn.getSnapshot().getElement().get(0), profileBaseFileName, profile); // genTypes(gen, row, extDefn.getSnapshot().getElement().get(0), profileBaseFileName, profile);
res.add(addCell(row, gen.new Cell(null, null, "("+(context.formatPhrase(RenderingContext.STRUC_DEF_COMPLEX))+")", null, null))); res.add(addCell(row, gen.new Cell(null, null, "("+(context.formatPhrase(RenderingContext.STRUC_DEF_COMPLEX))+")", null, null)));
res.add(generateDescription(gen, row, element, extDefn.getElement(), used.used, null, extDefn.getUrl(), profile, corePath, imagePath, root, logicalModel, allInvariants, valueDefn, snapshot, mustSupport, allowSubRows, rc)); res.add(generateDescription(gen, row, element, extDefn.getElement(), used.used, null, extDefn.getUrl(), profile, corePath, imagePath, root, logicalModel, allInvariants, valueDefn, snapshot, mustSupport, allowSubRows, rc, inScopeElements));
} }
} else { } else {
res.add(genCardinality(gen, element, row, hasDef, used, null)); res.add(genCardinality(gen, element, row, hasDef, used, null));
@ -1142,7 +1142,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
res.add(addCell(row, gen.new Cell())); res.add(addCell(row, gen.new Cell()));
else else
res.add(genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root, mustSupport)); res.add(genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root, mustSupport));
res.add(generateDescription(gen, row, element, (ElementDefinition) element.getUserData(ProfileUtilities.UD_DERIVATION_POINTER), used.used, null, null, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot, mustSupport, allowSubRows, rc)); res.add(generateDescription(gen, row, element, (ElementDefinition) element.getUserData(ProfileUtilities.UD_DERIVATION_POINTER), used.used, null, null, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot, mustSupport, allowSubRows, rc, inScopeElements));
} }
} }
} else if (element != null) { } else if (element != null) {
@ -1151,7 +1151,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
res.add(genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root, mustSupport)); res.add(genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root, mustSupport));
else else
res.add(addCell(row, gen.new Cell())); res.add(addCell(row, gen.new Cell()));
res.add(generateDescription(gen, row, element, (ElementDefinition) element.getUserData(ProfileUtilities.UD_DERIVATION_POINTER), used.used, null, null, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot, mustSupport, allowSubRows, rc)); res.add(generateDescription(gen, row, element, (ElementDefinition) element.getUserData(ProfileUtilities.UD_DERIVATION_POINTER), used.used, null, null, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot, mustSupport, allowSubRows, rc, inScopeElements));
} }
return res; return res;
} }
@ -1309,10 +1309,14 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
} }
public Cell generateDescription(HierarchicalTableGenerator gen, Row row, ElementDefinition definition, ElementDefinition fallback, boolean used, String baseURL, String url, StructureDefinition profile, String corePath, String imagePath, boolean root, boolean logicalModel, boolean allInvariants, boolean snapshot, boolean mustSupportOnly, boolean allowSubRows, RenderingContext rc) throws IOException, FHIRException { public Cell generateDescription(HierarchicalTableGenerator gen, Row row, ElementDefinition definition, ElementDefinition fallback, boolean used, String baseURL, String url, StructureDefinition profile, String corePath, String imagePath, boolean root, boolean logicalModel, boolean allInvariants, boolean snapshot, boolean mustSupportOnly, boolean allowSubRows, RenderingContext rc) throws IOException, FHIRException {
return generateDescription(gen, row, definition, fallback, used, baseURL, url, profile, corePath, imagePath, root, logicalModel, allInvariants, null, snapshot, mustSupportOnly, allowSubRows, rc); return generateDescription(gen, row, definition, fallback, used, baseURL, url, profile, corePath, imagePath, root, logicalModel, allInvariants, null, snapshot, mustSupportOnly, allowSubRows, rc, new ArrayList<ElementDefinition>());
} }
public Cell generateDescription(HierarchicalTableGenerator gen, Row row, ElementDefinition definition, ElementDefinition fallback, boolean used, String baseURL, String url, StructureDefinition profile, String corePath, String imagePath, boolean root, boolean logicalModel, boolean allInvariants, ElementDefinition valueDefn, boolean snapshot, boolean mustSupportOnly, boolean allowSubRows, RenderingContext rc) throws IOException, FHIRException { public Cell generateDescription(HierarchicalTableGenerator gen, Row row, ElementDefinition definition, ElementDefinition fallback, boolean used, String baseURL, String url, StructureDefinition profile, String corePath, String imagePath, boolean root, boolean logicalModel, boolean allInvariants, boolean snapshot, boolean mustSupportOnly, boolean allowSubRows, RenderingContext rc, List<ElementDefinition> inScopeElements) throws IOException, FHIRException {
return generateDescription(gen, row, definition, fallback, used, baseURL, url, profile, corePath, imagePath, root, logicalModel, allInvariants, null, snapshot, mustSupportOnly, allowSubRows, rc, inScopeElements);
}
public Cell generateDescription(HierarchicalTableGenerator gen, Row row, ElementDefinition definition, ElementDefinition fallback, boolean used, String baseURL, String url, StructureDefinition profile, String corePath, String imagePath, boolean root, boolean logicalModel, boolean allInvariants, ElementDefinition valueDefn, boolean snapshot, boolean mustSupportOnly, boolean allowSubRows, RenderingContext rc, List<ElementDefinition> inScopeElements) throws IOException, FHIRException {
Cell c = gen.new Cell(); Cell c = gen.new Cell();
row.getCells().add(c); row.getCells().add(c);
@ -1691,7 +1695,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
if (!definition.getPath().contains(".") && profile.hasExtension(ToolingExtensions.EXT_OBLIGATION_CORE, ToolingExtensions.EXT_OBLIGATION_TOOLS)) { if (!definition.getPath().contains(".") && profile.hasExtension(ToolingExtensions.EXT_OBLIGATION_CORE, ToolingExtensions.EXT_OBLIGATION_TOOLS)) {
obr.seeObligations(profile.getExtensionsByUrl(ToolingExtensions.EXT_OBLIGATION_CORE, ToolingExtensions.EXT_OBLIGATION_TOOLS)); obr.seeObligations(profile.getExtensionsByUrl(ToolingExtensions.EXT_OBLIGATION_CORE, ToolingExtensions.EXT_OBLIGATION_TOOLS));
} }
obr.renderTable(gen, c); obr.renderTable(gen, c, inScopeElements);
if (definition.hasMaxLength() && definition.getMaxLength()!=0) { if (definition.hasMaxLength() && definition.getMaxLength()!=0) {
if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); }
@ -3046,7 +3050,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
public XhtmlNode generateSpanningTable(StructureDefinition profile, String imageFolder, boolean onlyConstraints, String constraintPrefix, Set<String> outputTracker) throws IOException, FHIRException { public XhtmlNode generateSpanningTable(StructureDefinition profile, String imageFolder, boolean onlyConstraints, String constraintPrefix, Set<String> outputTracker) throws IOException, FHIRException {
HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, imageFolder, false, true); HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, imageFolder, false, true, "", "");
TableModel model = initSpanningTable(gen, "", false, profile.getId()); TableModel model = initSpanningTable(gen, "", false, profile.getId());
Set<String> processed = new HashSet<String>(); Set<String> processed = new HashSet<String>();
SpanEntry span = buildSpanningTable("(focus)", "", profile, processed, onlyConstraints, constraintPrefix); SpanEntry span = buildSpanningTable("(focus)", "", profile, processed, onlyConstraints, constraintPrefix);
@ -3149,8 +3153,8 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
return first ? null : x; return first ? null : x;
} }
public XhtmlNode generateExtensionTable(String defFile, StructureDefinition ed, String imageFolder, boolean inlineGraphics, boolean full, String corePath, String imagePath, Set<String> outputTracker, RenderingContext rc) throws IOException, FHIRException { public XhtmlNode generateExtensionTable(String defFile, StructureDefinition ed, String imageFolder, boolean inlineGraphics, boolean full, String corePath, String imagePath, Set<String> outputTracker, RenderingContext rc, String defPath, String anchorPrefix) throws IOException, FHIRException {
HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, imageFolder, inlineGraphics, true); HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, imageFolder, inlineGraphics, true, defPath, anchorPrefix);
TableModel model = gen.initNormalTable(corePath, false, true, ed.getId()+(full ? "f" : "n"), true, TableGenerationMode.XHTML); TableModel model = gen.initNormalTable(corePath, false, true, ed.getId()+(full ? "f" : "n"), true, TableGenerationMode.XHTML);
boolean deep = false; boolean deep = false;
@ -3211,7 +3215,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
r1.getCells().add(gen.new Cell(null, null, describeCardinality(c, null, new UnusedTracker()), null, null)); r1.getCells().add(gen.new Cell(null, null, describeCardinality(c, null, new UnusedTracker()), null, null));
genTypes(gen, r1, ved, defFile, ed, corePath, imagePath, false, false); genTypes(gen, r1, ved, defFile, ed, corePath, imagePath, false, false);
r1.setIcon("icon_"+m+"extension_simple.png", context.formatPhrase(RenderingContext.TEXT_ICON_EXTENSION_SIMPLE)); r1.setIcon("icon_"+m+"extension_simple.png", context.formatPhrase(RenderingContext.TEXT_ICON_EXTENSION_SIMPLE));
generateDescription(gen, r1, c, null, true, corePath, corePath, ed, corePath, imagePath, false, false, false, ved, false, false, false, rc); generateDescription(gen, r1, c, null, true, corePath, corePath, ed, corePath, imagePath, false, false, false, ved, false, false, false, rc, new ArrayList<ElementDefinition>());
} }
} }
} else { } else {
@ -3324,7 +3328,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
if (isProfiledExtension(ec)) { if (isProfiledExtension(ec)) {
StructureDefinition extDefn = context.getContext().fetchResource(StructureDefinition.class, ec.getType().get(0).getProfile().get(0).getValue()); StructureDefinition extDefn = context.getContext().fetchResource(StructureDefinition.class, ec.getType().get(0).getProfile().get(0).getValue());
if (extDefn == null) { if (extDefn == null) {
generateElementInner(t, sd, ec, 1, null, compareElement, null, false); generateElementInner(t, sd, ec, 1, null, compareElement, null, false, "", anchorPrefix, elements);
} else { } else {
ElementDefinition valueDefn = getExtensionValueDefinition(extDefn); ElementDefinition valueDefn = getExtensionValueDefinition(extDefn);
ElementDefinition compareValueDefn = null; ElementDefinition compareValueDefn = null;
@ -3332,15 +3336,15 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
StructureDefinition compareExtDefn = context.getContext().fetchResource(StructureDefinition.class, compareElement.getType().get(0).getProfile().get(0).getValue()); StructureDefinition compareExtDefn = context.getContext().fetchResource(StructureDefinition.class, compareElement.getType().get(0).getProfile().get(0).getValue());
compareValueDefn = getExtensionValueDefinition(extDefn); compareValueDefn = getExtensionValueDefinition(extDefn);
} catch (Exception except) {} } catch (Exception except) {}
generateElementInner(t, sd, ec, valueDefn == null || valueDefn.prohibited() ? 2 : 3, valueDefn, compareElement, compareValueDefn, false); generateElementInner(t, sd, ec, valueDefn == null || valueDefn.prohibited() ? 2 : 3, valueDefn, compareElement, compareValueDefn, false, "", anchorPrefix, elements);
// generateElementInner(b, extDefn, extDefn.getSnapshot().getElement().get(0), valueDefn == null ? 2 : 3, valueDefn); // generateElementInner(b, extDefn, extDefn.getSnapshot().getElement().get(0), valueDefn == null ? 2 : 3, valueDefn);
} }
} else { } else {
while (!dstack.isEmpty() && !isParent(dstack.peek(), ec)) { while (!dstack.isEmpty() && !isParent(dstack.peek(), ec)) {
finish(t, sd, dstack.pop(), mode); finish(t, sd, dstack.pop(), mode, "", anchorPrefix);
} }
dstack.push(ec); dstack.push(ec);
generateElementInner(t, sd, ec, mode, null, compareElement, null, false); generateElementInner(t, sd, ec, mode, null, compareElement, null, false, "", anchorPrefix, elements);
if (ec.hasSlicing()) { if (ec.hasSlicing()) {
generateSlicing(t, sd, ec, ec.getSlicing(), compareElement, mode, false); generateSlicing(t, sd, ec, ec.getSlicing(), compareElement, mode, false);
} }
@ -3350,12 +3354,12 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
i++; i++;
} }
while (!dstack.isEmpty()) { while (!dstack.isEmpty()) {
finish(t, sd, dstack.pop(), mode); finish(t, sd, dstack.pop(), mode, "", anchorPrefix);
} }
finish(t, sd, null, mode); finish(t, sd, null, mode, "", anchorPrefix);
} }
private void finish(XhtmlNode t, StructureDefinition sd, ElementDefinition ed, int mode) throws FHIRException, IOException { private void finish(XhtmlNode t, StructureDefinition sd, ElementDefinition ed, int mode, String defPath, String anchorPrefix) throws FHIRException, IOException {
for (Base b : VersionComparisonAnnotation.getDeleted(ed == null ? sd : ed, "element")) { for (Base b : VersionComparisonAnnotation.getDeleted(ed == null ? sd : ed, "element")) {
ElementDefinition ec = (ElementDefinition) b; ElementDefinition ec = (ElementDefinition) b;
@ -3365,7 +3369,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
sp.span("color: grey", null).tx("--"); sp.span("color: grey", null).tx("--");
sp.b().tx(". "+title); sp.b().tx(". "+title);
generateElementInner(t, sd, ec, mode, null, null, null, true); generateElementInner(t, sd, ec, mode, null, null, null, true, defPath, anchorPrefix, new ArrayList<ElementDefinition>());
if (ec.hasSlicing()) { if (ec.hasSlicing()) {
generateSlicing(t, sd, ec, ec.getSlicing(), null, mode, true); generateSlicing(t, sd, ec, ec.getSlicing(), null, mode, true);
} }
@ -3685,7 +3689,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
return "color:DarkGray;text-decoration:line-through"; return "color:DarkGray;text-decoration:line-through";
} }
private void generateElementInner(XhtmlNode tbl, StructureDefinition sd, ElementDefinition d, int mode, ElementDefinition value, ElementDefinition compare, ElementDefinition compareValue, boolean strikethrough) throws FHIRException, IOException { private void generateElementInner(XhtmlNode tbl, StructureDefinition sd, ElementDefinition d, int mode, ElementDefinition value, ElementDefinition compare, ElementDefinition compareValue, boolean strikethrough, String defPath, String anchorPrefix, List<ElementDefinition> inScopeElements) throws FHIRException, IOException {
boolean root = !d.getPath().contains("."); boolean root = !d.getPath().contains(".");
boolean slicedExtension = d.hasSliceName() && (d.getPath().endsWith(".extension") || d.getPath().endsWith(".modifierExtension")); boolean slicedExtension = d.hasSliceName() && (d.getPath().endsWith(".extension") || d.getPath().endsWith(".modifierExtension"));
// int slicedExtensionMode = (mode == GEN_MODE_KEY) && slicedExtension ? GEN_MODE_SNAP : mode; // see ProfileUtilities.checkExtensionDoco / Task 3970 // int slicedExtensionMode = (mode == GEN_MODE_KEY) && slicedExtension ? GEN_MODE_SNAP : mode; // see ProfileUtilities.checkExtensionDoco / Task 3970
@ -3779,7 +3783,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_COMP_PROF), "http://hl7.org/fhir/extensions/StructureDefinition-structuredefinition-compliesWithProfile.html", strikethrough, tableRow(tbl, context.formatPhrase(RenderingContext.STRUC_DEF_COMP_PROF), "http://hl7.org/fhir/extensions/StructureDefinition-structuredefinition-compliesWithProfile.html", strikethrough,
renderCanonicalListExt(context.formatPhrase(RenderingContext.STRUC_DEF_PROF_COMP)+" ", sd.getExtensionsByUrl(ToolingExtensions.EXT_SD_COMPLIES_WITH_PROFILE))); renderCanonicalListExt(context.formatPhrase(RenderingContext.STRUC_DEF_PROF_COMP)+" ", sd.getExtensionsByUrl(ToolingExtensions.EXT_SD_COMPLIES_WITH_PROFILE)));
} }
tableRow(tbl, context.formatPhrase(RenderingContext.GENERAL_OBLIG), null, strikethrough, describeObligations(d, root, sd)); tableRow(tbl, context.formatPhrase(RenderingContext.GENERAL_OBLIG), null, strikethrough, describeObligations(d, root, sd, defPath, anchorPrefix, inScopeElements));
if (d.hasExtension(ToolingExtensions.EXT_EXTENSION_STYLE)) { if (d.hasExtension(ToolingExtensions.EXT_EXTENSION_STYLE)) {
String es = d.getExtensionString(ToolingExtensions.EXT_EXTENSION_STYLE); String es = d.getExtensionString(ToolingExtensions.EXT_EXTENSION_STYLE);
@ -3981,7 +3985,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
} }
} }
private XhtmlNode describeObligations(ElementDefinition d, boolean root, StructureDefinition sdx) throws IOException { private XhtmlNode describeObligations(ElementDefinition d, boolean root, StructureDefinition sdx, String defPath, String anchorPrefix, List<ElementDefinition> inScopeElements) throws IOException {
XhtmlNode ret = new XhtmlNode(NodeType.Element, "div"); XhtmlNode ret = new XhtmlNode(NodeType.Element, "div");
ObligationsRenderer obr = new ObligationsRenderer(corePath, sdx, d.getPath(), context, hostMd, this); ObligationsRenderer obr = new ObligationsRenderer(corePath, sdx, d.getPath(), context, hostMd, this);
obr.seeObligations(d.getExtensionsByUrl(ToolingExtensions.EXT_OBLIGATION_CORE, ToolingExtensions.EXT_OBLIGATION_TOOLS)); obr.seeObligations(d.getExtensionsByUrl(ToolingExtensions.EXT_OBLIGATION_CORE, ToolingExtensions.EXT_OBLIGATION_TOOLS));
@ -4011,7 +4015,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
} }
if (obr.hasObligations()) { if (obr.hasObligations()) {
XhtmlNode tbl = ret.table("grid"); XhtmlNode tbl = ret.table("grid");
obr.renderTable(tbl.getChildNodes(), true); obr.renderTable(tbl.getChildNodes(), true, defPath, anchorPrefix, inScopeElements);
if (tbl.isEmpty()) { if (tbl.isEmpty()) {
ret.remove(tbl); ret.remove(tbl);
} }

View File

@ -439,33 +439,37 @@ public class TerminologyClientManager {
} }
public SourcedValueSet findValueSetOnServer(String canonical) { public SourcedValueSet findValueSetOnServer(String canonical) {
if (IGNORE_TX_REGISTRY || getMasterClient() == null || !useEcosystem) { if (IGNORE_TX_REGISTRY || getMasterClient() == null) {
return null; return null;
} }
String request = Utilities.pathURL(monitorServiceURL, "resolve?fhirVersion="+factory.getVersion()+"&valueSet="+Utilities.URLEncode(canonical)); String request = Utilities.pathURL(monitorServiceURL, "resolve?fhirVersion="+factory.getVersion()+"&valueSet="+Utilities.URLEncode(canonical));
if (usage != null) {
request = request + "&usage="+usage;
}
String server = null; String server = null;
try { try {
JsonObject json = JsonParser.parseObjectFromUrl(request); if (!useEcosystem) {
for (JsonObject item : json.getJsonObjects("authoritative")) { server = getMasterClient().getAddress();
if (server == null) { } else {
server = item.asString("url"); if (usage != null) {
request = request + "&usage="+usage;
} }
} JsonObject json = JsonParser.parseObjectFromUrl(request);
for (JsonObject item : json.getJsonObjects("candidates")) { for (JsonObject item : json.getJsonObjects("authoritative")) {
if (server == null) { if (server == null) {
server = item.asString("url"); server = item.asString("url");
}
} }
} for (JsonObject item : json.getJsonObjects("candidates")) {
if (server == null) { if (server == null) {
return null; server = item.asString("url");
} }
if (server.contains("://tx.fhir.org")) { }
try { if (server == null) {
server = server.replace("tx.fhir.org", new URL(getMasterClient().getAddress()).getHost()); return null;
} catch (MalformedURLException e) { }
if (server.contains("://tx.fhir.org")) {
try {
server = server.replace("tx.fhir.org", new URL(getMasterClient().getAddress()).getHost());
} catch (MalformedURLException e) {
}
} }
} }
TerminologyClientContext client = serverMap.get(server); TerminologyClientContext client = serverMap.get(server);

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.11-SNAPSHOT</version> <version>6.3.12-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.11-SNAPSHOT</version> <version>6.3.12-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -958,10 +958,12 @@ public class NpmPackage {
public String fhirVersion() { public String fhirVersion() {
if ("hl7.fhir.core".equals(npm.asString("name"))) if ("hl7.fhir.core".equals(npm.asString("name")))
return npm.asString("version"); return npm.asString("version");
else if (npm.asString("name").startsWith("hl7.fhir.r2.") || npm.asString("name").startsWith("hl7.fhir.r2b.") || npm.asString("name").startsWith("hl7.fhir.r3.") || else if (
npm.asString("name").startsWith("hl7.fhir.r4.") || npm.asString("name").startsWith("hl7.fhir.r4b.") || npm.asString("name").startsWith("hl7.fhir.r5.")) Utilities.existsInList(npm.asString("type"), "fhir.core", "fhir.examples") &&
Utilities.startsWithInList( npm.asString("name"), "hl7.fhir.r2.", "hl7.fhir.r2b.", "hl7.fhir.r3.",
"hl7.fhir.r4.", "hl7.fhir.r4b.", "hl7.fhir.r5.")) {
return npm.asString("version"); return npm.asString("version");
else { } else {
JsonObject dep = null; JsonObject dep = null;
if (npm.hasObject("dependencies")) { if (npm.hasObject("dependencies")) {
dep = npm.getJsonObject("dependencies"); dep = npm.getJsonObject("dependencies");

View File

@ -120,7 +120,7 @@ public class HierarchicalTableGenerator {
public static final int CONTINUE_SLICE = 5; public static final int CONTINUE_SLICE = 5;
private static final String BACKGROUND_ALT_COLOR = "#F7F7F7"; private static final String BACKGROUND_ALT_COLOR = "#F7F7F7";
public static boolean ACTIVE_TABLES = false; public static boolean ACTIVE_TABLES = false;
public enum TextAlignment { public enum TextAlignment {
LEFT, CENTER, RIGHT; LEFT, CENTER, RIGHT;
} }
@ -617,7 +617,9 @@ public class HierarchicalTableGenerator {
private String dest; private String dest;
private boolean makeTargets; private boolean makeTargets;
private String defPath = "";
private String anchorPrefix = "";
/** /**
* There are circumstances where the table has to present in the absence of a stable supporting infrastructure. * There are circumstances where the table has to present in the absence of a stable supporting infrastructure.
* and the file paths cannot be guaranteed. For these reasons, you can tell the builder to inline all the graphics * and the file paths cannot be guaranteed. For these reasons, you can tell the builder to inline all the graphics
@ -628,7 +630,7 @@ public class HierarchicalTableGenerator {
private TableGenerationMode mode; private TableGenerationMode mode;
private RenderingI18nContext i18n; private RenderingI18nContext i18n;
public HierarchicalTableGenerator(RenderingI18nContext i18n) { public HierarchicalTableGenerator(RenderingI18nContext i18n) {
super(); super();
this.i18n = i18n; this.i18n = i18n;
@ -643,6 +645,14 @@ public class HierarchicalTableGenerator {
checkSetup(); checkSetup();
} }
public String getDefPath() {
return defPath;
}
public String getAnchorPrefix() {
return anchorPrefix;
}
private void checkSetup() { private void checkSetup() {
if (dest == null) { if (dest == null) {
throw new Error("what"); throw new Error("what");
@ -650,6 +660,17 @@ public class HierarchicalTableGenerator {
} }
public HierarchicalTableGenerator(RenderingI18nContext i18n, String dest, boolean inlineGraphics, boolean makeTargets, String defPath, String anchorPrefix) {
super();
this.i18n = i18n;
this.dest = dest;
this.inLineGraphics = inlineGraphics;
this.makeTargets = makeTargets;
this.defPath = defPath;
this.anchorPrefix = anchorPrefix;
checkSetup();
}
public HierarchicalTableGenerator(RenderingI18nContext i18n, String dest, boolean inlineGraphics, boolean makeTargets) { public HierarchicalTableGenerator(RenderingI18nContext i18n, String dest, boolean inlineGraphics, boolean makeTargets) {
super(); super();
this.i18n = i18n; this.i18n = i18n;

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.11-SNAPSHOT</version> <version>6.3.12-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.11-SNAPSHOT</version> <version>6.3.12-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -887,6 +887,9 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
} }
validator.setJurisdiction(jurisdiction); validator.setJurisdiction(jurisdiction);
validator.setLogProgress(true); validator.setLogProgress(true);
if (policyAdvisor != null) {
validator.setPolicyAdvisor(policyAdvisor);
}
return validator; return validator;
} }
@ -1259,7 +1262,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
public List<StructureDefinition> getImpliedProfilesForResource(IResourceValidator validator, Object appContext, public List<StructureDefinition> getImpliedProfilesForResource(IResourceValidator validator, Object appContext,
String stackPath, ElementDefinition definition, StructureDefinition structure, Element resource, boolean valid, String stackPath, ElementDefinition definition, StructureDefinition structure, Element resource, boolean valid,
IMessagingServices msgServices, List<ValidationMessage> messages) { IMessagingServices msgServices, List<ValidationMessage> messages) {
return new BasePolicyAdvisorForFullValidation().getImpliedProfilesForResource(validator, appContext, stackPath, return new BasePolicyAdvisorForFullValidation(ReferenceValidationPolicy.CHECK_VALID).getImpliedProfilesForResource(validator, appContext, stackPath,
definition, structure, resource, valid, msgServices, messages); definition, structure, resource, valid, msgServices, messages);
} }

View File

@ -58,7 +58,7 @@ public class StandAloneValidatorFetcher extends BasePolicyAdvisorForFullValidati
private Map<String, NpmPackage> pidMap = new HashMap<>(); private Map<String, NpmPackage> pidMap = new HashMap<>();
public StandAloneValidatorFetcher(FilesystemPackageCacheManager pcm, IWorkerContext context, IPackageInstaller installer) { public StandAloneValidatorFetcher(FilesystemPackageCacheManager pcm, IWorkerContext context, IPackageInstaller installer) {
super(); super(ReferenceValidationPolicy.IGNORE);
this.pcm = pcm; this.pcm = pcm;
this.context = context; this.context = context;
this.installer = installer; this.installer = installer;
@ -74,7 +74,7 @@ public class StandAloneValidatorFetcher extends BasePolicyAdvisorForFullValidati
Object appContext, Object appContext,
String path, String path,
String url) { String url) {
return ReferenceValidationPolicy.CHECK_TYPE_IF_EXISTS; return ReferenceValidationPolicy.IGNORE;
} }
@Override @Override

View File

@ -568,6 +568,7 @@ public class ValidationService {
StandAloneValidatorFetcher fetcher = new StandAloneValidatorFetcher(validationEngine.getPcm(), validationEngine.getContext(), validationEngine); StandAloneValidatorFetcher fetcher = new StandAloneValidatorFetcher(validationEngine.getPcm(), validationEngine.getContext(), validationEngine);
validationEngine.setFetcher(fetcher); validationEngine.setFetcher(fetcher);
validationEngine.getContext().setLocator(fetcher); validationEngine.getContext().setLocator(fetcher);
validationEngine.setPolicyAdvisor(fetcher);
} }
validationEngine.getBundleValidationRules().addAll(cliContext.getBundleValidationRules()); validationEngine.getBundleValidationRules().addAll(cliContext.getBundleValidationRules());
validationEngine.setJurisdiction(CodeSystemUtilities.readCoding(cliContext.getJurisdiction())); validationEngine.setJurisdiction(CodeSystemUtilities.readCoding(cliContext.getJurisdiction()));

View File

@ -27,10 +27,17 @@ import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
public class BasePolicyAdvisorForFullValidation implements IValidationPolicyAdvisor { public class BasePolicyAdvisorForFullValidation implements IValidationPolicyAdvisor {
private ReferenceValidationPolicy refpol = ReferenceValidationPolicy.CHECK_VALID;
public BasePolicyAdvisorForFullValidation(ReferenceValidationPolicy refpol) {
super();
this.refpol = refpol;
}
@Override @Override
public ReferenceValidationPolicy policyForReference(IResourceValidator validator, Object appContext, String path, String url) { public ReferenceValidationPolicy policyForReference(IResourceValidator validator, Object appContext, String path, String url) {
return ReferenceValidationPolicy.CHECK_TYPE_IF_EXISTS; return refpol;
} }
@Override @Override

View File

@ -596,7 +596,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private boolean noBindingMsgSuppressed; private boolean noBindingMsgSuppressed;
private Map<String, Element> fetchCache = new HashMap<>(); private Map<String, Element> fetchCache = new HashMap<>();
private HashMap<Element, ResourceValidationTracker> resourceTracker = new HashMap<>(); private HashMap<Element, ResourceValidationTracker> resourceTracker = new HashMap<>();
private IValidationPolicyAdvisor policyAdvisor = new BasePolicyAdvisorForFullValidation(); private IValidationPolicyAdvisor policyAdvisor = new BasePolicyAdvisorForFullValidation(ReferenceValidationPolicy.CHECK_VALID);
long time = 0; long time = 0;
long start = 0; long start = 0;
long lastlog = 0; long lastlog = 0;
@ -1029,7 +1029,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
validateResource(new ValidationContext(appContext, element), errors, element, element, defn, resourceIdRule, stack.resetIds(), null, new ValidationMode(ValidationReason.Validation, ProfileSource.ConfigProfile), false, false); validateResource(new ValidationContext(appContext, element), errors, element, element, defn, resourceIdRule, stack.resetIds(), null, new ValidationMode(ValidationReason.Validation, ProfileSource.ConfigProfile), false, false);
} }
} }
if (hintAboutNonMustSupport) { if (hintAboutNonMustSupport && !profiles.isEmpty()) {
checkElementUsage(errors, element, stack); checkElementUsage(errors, element, stack);
} }
codingObserver.finish(errors, stack); codingObserver.finish(errors, stack);
@ -1042,10 +1042,19 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private void checkElementUsage(List<ValidationMessage> errors, Element element, NodeStack stack) { private void checkElementUsage(List<ValidationMessage> errors, Element element, NodeStack stack) {
String elementUsage = element.getUserString("elementSupported"); if (element.getPath()==null
hint(errors, NO_RULE_DATE, IssueType.INFORMATIONAL, element.line(), element.col(), stack.getLiteralPath(), elementUsage == null || elementUsage.equals("Y"), I18nConstants.MUSTSUPPORT_VAL_MUSTSUPPORT, element.getName(), element.getProperty().getStructure().getVersionedUrl()); || (element.getName().equals("id") && !element.getPath().substring(0, element.getPath().length()-3).contains("."))
|| (element.getName().equals("text") && !element.getPath().substring(0, element.getPath().length()-5).contains(".")))
return;
String hasFixed = element.getUserString("hasFixed");
if (element.getPath().contains(".") && (hasFixed== null || !hasFixed.equals("Y"))) {
String elementUsage = element.getUserString("elementSupported");
hint(errors, NO_RULE_DATE, IssueType.INFORMATIONAL, element.line(), element.col(), stack.getLiteralPath(), elementUsage != null && (elementUsage.equals("Y") || elementUsage.equals("NA")), I18nConstants.MUSTSUPPORT_VAL_MUSTSUPPORT, element.getName(), element.getProperty().getStructure().getVersionedUrl());
if (elementUsage==null || !elementUsage.equals("Y"))
return;
}
if (element.hasChildren()) { if (element.hasChildren() && (hasFixed== null || !hasFixed.equals("Y"))) {
String prevName = ""; String prevName = "";
int elementCount = 0; int elementCount = 0;
for (Element ce : element.getChildren()) { for (Element ce : element.getChildren()) {
@ -6745,13 +6754,16 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
} }
profile.setUserData("usesMustSupport", usesMustSupport); profile.setUserData("usesMustSupport", usesMustSupport);
} }
if (usesMustSupport.equals("Y")) { String elementSupported = ei.getElement().getUserString("elementSupported");
String elementSupported = ei.getElement().getUserString("elementSupported"); String fixedValue = ei.getElement().getUserString("hasFixed");
if (elementSupported == null || ei.definition.getMustSupport()) if ((elementSupported == null || !elementSupported.equals("Y")) && ei.definition.getMustSupport()) {
if (ei.definition.getMustSupport()) { if (ei.definition.getMustSupport()) {
ei.getElement().setUserData("elementSupported", "Y"); ei.getElement().setUserData("elementSupported", "Y");
} }
} } else if (elementSupported == null && !usesMustSupport.equals("Y"))
ei.getElement().setUserData("elementSupported", "NA");
if (fixedValue==null && (ei.definition.hasFixed() || ei.definition.hasPattern()))
ei.getElement().setUserData("hasFixed", "Y");
} }
public boolean checkCardinalities(List<ValidationMessage> errors, StructureDefinition profile, Element element, NodeStack stack, public boolean checkCardinalities(List<ValidationMessage> errors, StructureDefinition profile, Element element, NodeStack stack,

View File

@ -1,5 +1,5 @@
package org.hl7.fhir.validation.profile; package org.hl7.fhir.validation.profile;
/* /*
Copyright (c) 2011+, HL7, Inc. Copyright (c) 2011+, HL7, Inc.
All rights reserved. All rights reserved.
@ -28,138 +28,140 @@ package org.hl7.fhir.validation.profile;
POSSIBILITY OF SUCH DAMAGE. POSSIBILITY OF SUCH DAMAGE.
*/ */
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.List; import java.util.List;
import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.fhirpath.FHIRPathEngine; import org.hl7.fhir.r5.fhirpath.FHIRPathEngine;
import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionConstraintComponent; import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionConstraintComponent;
import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent; import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent;
import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind; import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
import org.hl7.fhir.r5.utils.XVerExtensionManager; import org.hl7.fhir.r5.utils.XVerExtensionManager;
import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
import org.hl7.fhir.validation.BaseValidator; import org.hl7.fhir.validation.BaseValidator;
public class ProfileValidator extends BaseValidator { public class ProfileValidator extends BaseValidator {
private boolean checkAggregation = false; private boolean checkAggregation = false;
private boolean checkMustSupport = false; private boolean checkMustSupport = false;
private boolean allowDoubleQuotesInFHIRPath = false; private boolean allowDoubleQuotesInFHIRPath = false;
private FHIRPathEngine fpe; private FHIRPathEngine fpe;
public ProfileValidator(IWorkerContext context, XVerExtensionManager xverManager) { public ProfileValidator(IWorkerContext context, XVerExtensionManager xverManager) {
super(context, xverManager, false); super(context, xverManager, false);
fpe = new FHIRPathEngine(context); fpe = new FHIRPathEngine(context);
fpe.setAllowDoubleQuotes(allowDoubleQuotesInFHIRPath); fpe.setAllowDoubleQuotes(allowDoubleQuotesInFHIRPath);
} }
public boolean isCheckAggregation() { public boolean isCheckAggregation() {
return checkAggregation; return checkAggregation;
} }
public boolean isCheckMustSupport() { public boolean isCheckMustSupport() {
return checkMustSupport; return checkMustSupport;
} }
public void setCheckAggregation(boolean checkAggregation) { public void setCheckAggregation(boolean checkAggregation) {
this.checkAggregation = checkAggregation; this.checkAggregation = checkAggregation;
} }
public void setCheckMustSupport(boolean checkMustSupport) { public void setCheckMustSupport(boolean checkMustSupport) {
this.checkMustSupport = checkMustSupport; this.checkMustSupport = checkMustSupport;
} }
public boolean isAllowDoubleQuotesInFHIRPath() { public boolean isAllowDoubleQuotesInFHIRPath() {
return allowDoubleQuotesInFHIRPath; return allowDoubleQuotesInFHIRPath;
} }
public void setAllowDoubleQuotesInFHIRPath(boolean allowDoubleQuotesInFHIRPath) { public void setAllowDoubleQuotesInFHIRPath(boolean allowDoubleQuotesInFHIRPath) {
this.allowDoubleQuotesInFHIRPath = allowDoubleQuotesInFHIRPath; this.allowDoubleQuotesInFHIRPath = allowDoubleQuotesInFHIRPath;
} }
protected boolean rule(List<ValidationMessage> errors, IssueType type, String path, boolean b, String msg) { protected boolean rule(List<ValidationMessage> errors, IssueType type, String path, boolean b, String msg) {
String rn = path.contains(".") ? path.substring(0, path.indexOf(".")) : path; String rn = path.contains(".") ? path.substring(0, path.indexOf(".")) : path;
return super.ruleHtml(errors, NO_RULE_DATE, type, path, b, msg, "<a href=\""+(rn.toLowerCase())+".html\">"+rn+"</a>: "+Utilities.escapeXml(msg)); return super.ruleHtml(errors, NO_RULE_DATE, type, path, b, msg, "<a href=\""+(rn.toLowerCase())+".html\">"+rn+"</a>: "+Utilities.escapeXml(msg));
} }
public List<ValidationMessage> validate(StructureDefinition profile, boolean forBuild) { public List<ValidationMessage> validate(StructureDefinition profile, boolean forBuild) {
List<ValidationMessage> errors = new ArrayList<ValidationMessage>(); List<ValidationMessage> errors = new ArrayList<ValidationMessage>();
// must have a FHIR version- GF#3160 // must have a FHIR version- GF#3160
String s = (profile.getKind() == StructureDefinitionKind.LOGICAL) ? "Logical Models" : "Profiles"; String s = (profile.getKind() == StructureDefinitionKind.LOGICAL) ? "Logical Models" : "Profiles";
warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, profile.getUrl(), profile.hasFhirVersion(), s+" SHOULD state the FHIR Version on which they are based"); warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, profile.getUrl(), profile.hasFhirVersion(), s+" SHOULD state the FHIR Version on which they are based");
warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, profile.getUrl(), profile.hasVersion(), s+" SHOULD state their own version"); warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, profile.getUrl(), profile.hasVersion(), s+" SHOULD state their own version");
// extensions must be defined // extensions must be defined
for (ElementDefinition ec : profile.getDifferential().getElement()) for (ElementDefinition ec : profile.getDifferential().getElement())
checkExtensions(profile, errors, "differential", ec); checkExtensions(profile, errors, "differential", ec);
rule(errors, NO_RULE_DATE, IssueType.STRUCTURE, profile.getId(), profile.hasSnapshot(), "missing Snapshot at "+profile.getName()+"."+profile.getName()); rule(errors, NO_RULE_DATE, IssueType.STRUCTURE, profile.getId(), profile.hasSnapshot(), "missing Snapshot at "+profile.getName()+"."+profile.getName());
for (ElementDefinition ec : profile.getSnapshot().getElement()) for (ElementDefinition ec : profile.getSnapshot().getElement())
checkExtensions(profile, errors, "snapshot", ec); checkExtensions(profile, errors, "snapshot", ec);
if (rule(errors, NO_RULE_DATE, IssueType.STRUCTURE, profile.getId(), profile.hasSnapshot(), "A snapshot is required")) { if (rule(errors, NO_RULE_DATE, IssueType.STRUCTURE, profile.getId(), profile.hasSnapshot(), "A snapshot is required")) {
Hashtable<String, ElementDefinition> snapshotElements = new Hashtable<String, ElementDefinition>(); Hashtable<String, ElementDefinition> snapshotElements = new Hashtable<String, ElementDefinition>();
for (ElementDefinition ed : profile.getSnapshot().getElement()) { for (ElementDefinition ed : profile.getSnapshot().getElement()) {
snapshotElements.put(ed.getId(), ed); snapshotElements.put(ed.getId(), ed);
for (ElementDefinitionConstraintComponent inv : ed.getConstraint()) { for (ElementDefinitionConstraintComponent inv : ed.getConstraint()) {
if (forBuild) { if (forBuild) {
if (!inExemptList(inv.getKey())) { if (!inExemptList(inv.getKey())) {
// if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, profile.getId()+"::"+ed.getPath()+"::"+inv.getKey(), inv.hasExpression(), "The invariant has no FHIR Path expression ("+inv.getXpath()+")")) { // if (rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, profile.getId()+"::"+ed.getPath()+"::"+inv.getKey(), inv.hasExpression(), "The invariant has no FHIR Path expression ("+inv.getXpath()+")")) {
// try { // try {
// fpe.check(null, profile.getType(), ed.getPath(), inv.getExpression()); // , inv.hasXpath() && inv.getXpath().startsWith("@value") // fpe.check(null, profile.getType(), ed.getPath(), inv.getExpression()); // , inv.hasXpath() && inv.getXpath().startsWith("@value")
// } catch (Exception e) { // } catch (Exception e) {
// // rule(errors, UNKNOWN_DATE_TIME, IssueType.STRUCTURE, profile.getId()+"::"+ed.getPath()+"::"+inv.getId(), false, e.getMessage()); // // rule(errors, UNKNOWN_DATE_TIME, IssueType.STRUCTURE, profile.getId()+"::"+ed.getPath()+"::"+inv.getId(), false, e.getMessage());
// } // }
// } // }
} }
} }
} }
} }
if (snapshotElements != null) { if (snapshotElements != null) {
for (ElementDefinition diffElement : profile.getDifferential().getElement()) { for (ElementDefinition diffElement : profile.getDifferential().getElement()) {
if (diffElement == null) if (diffElement == null)
throw new Error("Diff Element is null - this is not an expected thing"); throw new Error("Diff Element is null - this is not an expected thing");
ElementDefinition snapElement = snapshotElements.get(diffElement.getId()); ElementDefinition snapElement = snapshotElements.get(diffElement.getId());
if (snapElement!=null) { // Happens with profiles in the main build - should be able to fix once snapshot generation is fixed - Lloyd if (snapElement!=null) { // Happens with profiles in the main build - should be able to fix once snapshot generation is fixed - Lloyd
warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, diffElement.getId(), !checkMustSupport || snapElement.hasMustSupport(), "Elements included in the differential should declare mustSupport"); // We don't care about mustSupport for the root element, if the element is just declaring slicing, if there's a pattern or fixed value, or if the element is being prohibited.
if (checkAggregation) { boolean noMustSupport = !checkMustSupport || !snapElement.getPath().contains(".") || snapElement.hasSlicing() || snapElement.hasPattern() || snapElement.hasFixed() || snapElement.getMax().equals("0") || snapElement.hasMustSupport();
for (TypeRefComponent type : snapElement.getType()) { warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, diffElement.getId(), noMustSupport, "Elements included in the differential that aren't prohibited and don't have fixed values or patterns should declare mustSupport: " + snapElement.getPath());
if ("http://hl7.org/fhir/Reference".equals(type.getWorkingCode()) || "http://hl7.org/fhir/canonical".equals(type.getWorkingCode())) { if (checkAggregation) {
warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, diffElement.getId(), type.hasAggregation(), "Elements with type Reference or canonical should declare aggregation"); for (TypeRefComponent type : snapElement.getType()) {
} if ("http://hl7.org/fhir/Reference".equals(type.getWorkingCode()) || "http://hl7.org/fhir/canonical".equals(type.getWorkingCode())) {
} warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, diffElement.getId(), type.hasAggregation(), "Elements with type Reference or canonical should declare aggregation");
} }
} }
} }
} }
} }
return errors; }
} }
return errors;
// these are special cases }
private boolean inExemptList(String key) {
return key.startsWith("txt-"); // these are special cases
} private boolean inExemptList(String key) {
return key.startsWith("txt-");
private boolean checkExtensions(StructureDefinition profile, List<ValidationMessage> errors, String kind, ElementDefinition ec) { }
if (!ec.getType().isEmpty() && "Extension".equals(ec.getType().get(0).getWorkingCode()) && ec.getType().get(0).hasProfile()) {
String url = ec.getType().get(0).getProfile().get(0).getValue(); private boolean checkExtensions(StructureDefinition profile, List<ValidationMessage> errors, String kind, ElementDefinition ec) {
StructureDefinition defn = context.fetchResource(StructureDefinition.class, url); if (!ec.getType().isEmpty() && "Extension".equals(ec.getType().get(0).getWorkingCode()) && ec.getType().get(0).hasProfile()) {
if (defn == null) { String url = ec.getType().get(0).getProfile().get(0).getValue();
defn = getXverExt(profile, errors, url); StructureDefinition defn = context.fetchResource(StructureDefinition.class, url);
} if (defn == null) {
return rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, profile.getId(), defn != null, "Unable to find Extension '"+url+"' referenced at "+profile.getUrl()+" "+kind+" "+ec.getPath()+" ("+ec.getSliceName()+")"); defn = getXverExt(profile, errors, url);
} else { }
return true; return rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, profile.getId(), defn != null, "Unable to find Extension '"+url+"' referenced at "+profile.getUrl()+" "+kind+" "+ec.getPath()+" ("+ec.getSliceName()+")");
} } else {
} return true;
}
}
} }

View File

@ -894,7 +894,7 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe
public List<StructureDefinition> getImpliedProfilesForResource(IResourceValidator validator, Object appContext, public List<StructureDefinition> getImpliedProfilesForResource(IResourceValidator validator, Object appContext,
String stackPath, ElementDefinition definition, StructureDefinition structure, Element resource, boolean valid, String stackPath, ElementDefinition definition, StructureDefinition structure, Element resource, boolean valid,
IMessagingServices msgServices, List<ValidationMessage> messages) { IMessagingServices msgServices, List<ValidationMessage> messages) {
return new BasePolicyAdvisorForFullValidation().getImpliedProfilesForResource(validator, appContext, stackPath, return new BasePolicyAdvisorForFullValidation(ReferenceValidationPolicy.CHECK_VALID).getImpliedProfilesForResource(validator, appContext, stackPath,
definition, structure, resource, valid, msgServices, messages); definition, structure, resource, valid, msgServices, messages);
} }
} }

View File

@ -5,10 +5,13 @@ import java.util.Locale;
import org.hl7.fhir.r5.terminologies.utilities.TerminologyCache; import org.hl7.fhir.r5.terminologies.utilities.TerminologyCache;
import org.hl7.fhir.r5.test.utils.TestingUtilities; import org.hl7.fhir.r5.test.utils.TestingUtilities;
import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy;
import org.hl7.fhir.utilities.FhirPublication; import org.hl7.fhir.utilities.FhirPublication;
import org.hl7.fhir.utilities.tests.TestConfig; import org.hl7.fhir.utilities.tests.TestConfig;
import org.hl7.fhir.utilities.tests.TestConstants; import org.hl7.fhir.utilities.tests.TestConstants;
import org.hl7.fhir.validation.ValidationEngine; import org.hl7.fhir.validation.ValidationEngine;
import org.hl7.fhir.validation.cli.services.StandAloneValidatorFetcher;
import org.hl7.fhir.validation.instance.BasePolicyAdvisorForFullValidation;
public class TestUtilities { public class TestUtilities {
@ -64,6 +67,7 @@ public class TestUtilities {
TerminologyCache.setCacheErrors(true); TerminologyCache.setCacheErrors(true);
} }
validationEngine.setPolicyAdvisor(new BasePolicyAdvisorForFullValidation(ReferenceValidationPolicy.IGNORE));
return validationEngine; return validationEngine;
} }

View File

@ -1,5 +1,6 @@
{ {
"http://hl7.org/fhir/ValueSet/ucum-vitals-common|4.0.0" : null, "http://hl7.org/fhir/ValueSet/ucum-vitals-common|4.0.0" : null,
"http://loinc.org/vs" : null,
"http://hl7.org.au/fhir/ValueSet/au-hl7v2-0203" : null, "http://hl7.org.au/fhir/ValueSet/au-hl7v2-0203" : null,
"http://hl7.org/fhir/ValueSet/name-use|4.0.1" : null, "http://hl7.org/fhir/ValueSet/name-use|4.0.1" : null,
"http://hl7.org/fhir/ValueSet/observation-status|4.0.0" : null, "http://hl7.org/fhir/ValueSet/observation-status|4.0.0" : null,

View File

@ -14,14 +14,14 @@
HAPI FHIR HAPI FHIR
--> -->
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>6.3.11-SNAPSHOT</version> <version>6.3.12-SNAPSHOT</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<properties> <properties>
<commons_compress_version>1.26.0</commons_compress_version> <commons_compress_version>1.26.0</commons_compress_version>
<guava_version>32.0.1-jre</guava_version> <guava_version>32.0.1-jre</guava_version>
<hapi_fhir_version>6.4.1</hapi_fhir_version> <hapi_fhir_version>6.4.1</hapi_fhir_version>
<validator_test_case_version>1.5.11-SNAPSHOT</validator_test_case_version> <validator_test_case_version>1.5.11</validator_test_case_version>
<jackson_version>2.17.0</jackson_version> <jackson_version>2.17.0</jackson_version>
<junit_jupiter_version>5.9.2</junit_jupiter_version> <junit_jupiter_version>5.9.2</junit_jupiter_version>
<junit_platform_launcher_version>1.8.2</junit_platform_launcher_version> <junit_platform_launcher_version>1.8.2</junit_platform_launcher_version>