Merge pull request #1055 from hapifhir/gg-202301-profile-rendering

Gg 202301 profile rendering
This commit is contained in:
Grahame Grieve 2023-01-04 15:31:31 +11:00 committed by GitHub
commit ff0fd98539
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 3876 additions and 2852 deletions

View File

@ -13,8 +13,8 @@ import org.hl7.fhir.r5.comparison.CodeSystemComparer.CodeSystemComparison;
import org.hl7.fhir.r5.comparison.ProfileComparer.ProfileComparison;
import org.hl7.fhir.r5.comparison.ResourceComparer.ResourceComparison;
import org.hl7.fhir.r5.comparison.ValueSetComparer.ValueSetComparison;
import org.hl7.fhir.r5.conformance.profile.ProfileKnowledgeProvider;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.ProfileKnowledgeProvider;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.CapabilityStatement;

View File

@ -11,7 +11,6 @@ import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.comparison.ValueSetComparer.ValueSetComparison;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.UnusedTracker;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.formats.IParser;
import org.hl7.fhir.r5.formats.JsonParser;
@ -33,10 +32,16 @@ import org.hl7.fhir.r5.model.StringType;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.renderers.StructureDefinitionRenderer;
import org.hl7.fhir.r5.renderers.utils.RenderingContext;
import org.hl7.fhir.r5.renderers.utils.RenderingContext.GenerationRules;
import org.hl7.fhir.r5.renderers.utils.RenderingContext.ResourceRendererMode;
import org.hl7.fhir.r5.utils.DefinitionNavigator;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.MarkDownProcessor;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationOptions;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator;
import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Cell;
@ -988,22 +993,27 @@ public class ProfileComparer extends CanonicalResourceComparer {
String sn = getSliceName(combined);
if (sn != null)
sName = sName +":"+sn;
UnusedTracker used = new UnusedTracker();
StructureDefinitionRenderer.UnusedTracker used = new StructureDefinitionRenderer.UnusedTracker();
StructureDefinitionRenderer sdrLeft = new StructureDefinitionRenderer(new RenderingContext(utilsLeft.getContext(), null, utilsLeft.getTerminologyServiceOptions(), corePath, prefix, null, ResourceRendererMode.TECHNICAL, GenerationRules.IG_PUBLISHER));
StructureDefinitionRenderer sdrRight= new StructureDefinitionRenderer(new RenderingContext(utilsRight.getContext(), null, utilsRight.getTerminologyServiceOptions(), corePath, prefix, null, ResourceRendererMode.TECHNICAL, GenerationRules.IG_PUBLISHER));
Cell nc;
String leftColor = !combined.hasLeft() ? COLOR_NO_ROW_LEFT : combined.hasErrors() ? COLOR_DIFFERENT : null;
String rightColor = !combined.hasRight() ? COLOR_NO_ROW_LEFT : combined.hasErrors() ? COLOR_DIFFERENT : null;
if (combined.hasLeft()) {
nc = utilsLeft.genElementNameCell(gen, combined.getLeft().getDef(), "??", true, corePath, prefix, root, false, false, combined.getLeft().getSrc(), typesRow, row, false, ext, used , ref, sName, null);
nc = sdrLeft.genElementNameCell(gen, combined.getLeft().getDef(), "??", true, corePath, prefix, root, false, false, combined.getLeft().getSrc(), typesRow, row, false, ext, used , ref, sName, null);
} else {
nc = utilsRight.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()) {
frame(utilsLeft.genElementCells(gen, combined.getLeft().getDef(), "??", true, corePath, prefix, root, false, false, combined.getLeft().getSrc(), typesRow, row, true, ext, used , ref, sName, nc, false, false, null), 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, null), leftColor);
} else {
frame(spacers(row, 4, gen), leftColor);
}
if (combined.hasRight()) {
frame(utilsRight.genElementCells(gen, combined.getRight().getDef(), "??", true, corePath, prefix, root, false, false, combined.getRight().getSrc(), typesRow, row, true, ext, used, ref, sName, nc, false, false, null), 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, null), rightColor);
} else {
frame(spacers(row, 4, gen), rightColor);
}

View File

@ -4,18 +4,29 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.conformance.profile.BindingResolution;
import org.hl7.fhir.r5.conformance.profile.ProfileKnowledgeProvider;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.ProfileKnowledgeProvider;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.ProfileKnowledgeProvider.BindingResolution;
import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingAdditionalComponent;
import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent;
import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.Extension;
import org.hl7.fhir.r5.model.PrimitiveType;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.UsageContext;
import org.hl7.fhir.r5.renderers.CodeResolver;
import org.hl7.fhir.r5.renderers.CodeResolver.CodeResolution;
import org.hl7.fhir.r5.renderers.DataRenderer;
import org.hl7.fhir.r5.renderers.IMarkdownProcessor;
import org.hl7.fhir.r5.renderers.utils.RenderingContext;
import org.hl7.fhir.r5.utils.PublicationHacker;
import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.utilities.MarkDownProcessor;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator;
import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Cell;
@ -23,6 +34,7 @@ import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Piece;
import org.hl7.fhir.utilities.xhtml.NodeType;
import org.hl7.fhir.utilities.xhtml.XhtmlComposer;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
import org.hl7.fhir.utilities.xhtml.XhtmlNodeList;
public class AdditionalBindingsRenderer {
public class AdditionalBindingDetail {
@ -78,14 +90,16 @@ public class AdditionalBindingsRenderer {
private String path;
private RenderingContext context;
private IMarkdownProcessor md;
private CodeResolver cr;
public AdditionalBindingsRenderer(ProfileKnowledgeProvider pkp, String corePath, StructureDefinition profile, String path, RenderingContext context, IMarkdownProcessor md) {
public AdditionalBindingsRenderer(ProfileKnowledgeProvider pkp, String corePath, StructureDefinition profile, String path, RenderingContext context, IMarkdownProcessor md, CodeResolver cr) {
this.pkp = pkp;
this.corePath = corePath;
this.profile = profile;
this.path = path;
this.context = context;
this.md = md;
this.cr = cr;
}
public void seeMaxBinding(Extension ext) {
@ -106,7 +120,7 @@ public class AdditionalBindingsRenderer {
abr.compare = new AdditionalBindingDetail();
abr.compare.valueSet = compExt==null ? null : compExt.getValue().primitiveValue();
} else {
abr.isUnchanged = ext.hasUserData(ProfileUtilities.DERIVATION_EQUALS);
abr.isUnchanged = ext.hasUserData(ProfileUtilities.UD_DERIVATION_EQUALS);
}
bindings.add(abr);
}
@ -166,7 +180,7 @@ public class AdditionalBindingsRenderer {
abr.docoShort = ext.getExtensionString("shortDoco");
abr.usage = (ext.hasExtension("usage")) && ext.getExtensionByUrl("usage").hasValueUsageContext() ? ext.getExtensionByUrl("usage").getValueUsageContext() : null;
abr.any = "any".equals(ext.getExtensionString("scope"));
abr.isUnchanged = ext.hasUserData(ProfileUtilities.DERIVATION_EQUALS);
abr.isUnchanged = ext.hasUserData(ProfileUtilities.UD_DERIVATION_EQUALS);
return abr;
}
@ -309,16 +323,19 @@ public class AdditionalBindingsRenderer {
case "minimum":
td.ah(corePath+"extension-elementdefinition-minvalueset.html", "The minimum allowable value set - any conformant system SHALL support all these codes").tx("Min Binding");
break;
case "conformance" :
case "required" :
td.ah(corePath+"terminologies.html#strength", "Validators will check this binding (strength = required)").tx("Validation Binding");
break;
case "extensible" :
td.ah(corePath+"terminologies.html#strength", "Validators will check this binding (strength = extensible)").tx("Validation Binding");
break;
case "candidate" :
td.ah(corePath+"terminologies.html#strength", "This is a candidate binding that constraints on this profile may consider (see doco)").tx("Candidate Validation Binding");
break;
case "current" :
td.span(null, "New records are required to use this value set, but legacy records may use other codes").tx("Required");
break;
case "recommended" :
case "preferred" :
td.span(null, "This is the value set that is recommended (documentation should explain why)").tx("Recommended");
break;
case "ui" :
@ -346,5 +363,60 @@ public class AdditionalBindingsRenderer {
return !bindings.isEmpty();
}
public void render(XhtmlNodeList children, List<ElementDefinitionBindingAdditionalComponent> list) {
if (list.size() == 1) {
render(children, list.get(0));
} else {
XhtmlNode ul = children.ul();
for (ElementDefinitionBindingAdditionalComponent b : list) {
render(ul.li().getChildNodes(), b);
}
}
}
private void render(XhtmlNodeList children, ElementDefinitionBindingAdditionalComponent b) {
if (b.getValueSet() == null) {
return; // what should happen?
}
BindingResolution br = pkp.resolveBinding(profile, b.getValueSet(), corePath);
XhtmlNode a = children.ah(br.url == null ? null : Utilities.isAbsoluteUrl(br.url) || !context.getPkp().prependLinks() ? br.url : corePath+br.url, b.hasDocumentation() ? b.getDocumentation() : null);
if (b.hasDocumentation()) {
a.attribute("title", b.getDocumentation());
}
a.tx(br.display);
if (b.hasShortDoco()) {
children.tx(": ");
children.tx(b.getShortDoco());
}
if (b.getAny() || b.hasUsage()) {
children.tx(" (");
boolean ffirst = !b.getAny();
if (b.getAny()) {
children.tx("any repeat");
}
for (UsageContext uc : b.getUsage()) {
if (ffirst) ffirst = false; else children.tx(",");
if (!uc.getCode().is("http://terminology.hl7.org/CodeSystem/usage-context-type", "jurisdiction")) {
children.tx(displayForUsage(uc.getCode()));
children.tx("=");
}
CodeResolution ccr = cr.resolveCode(uc.getValueCodeableConcept());
children.ah(ccr.getLink(), ccr.getHint()).tx(ccr.getDisplay());
}
children.tx(")");
}
}
private String displayForUsage(Coding c) {
if (c.hasDisplay()) {
return c.getDisplay();
}
if ("http://terminology.hl7.org/CodeSystem/usage-context-type".equals(c.getSystem())) {
return c.getCode();
}
return c.getCode();
}
}

View File

@ -0,0 +1,13 @@
package org.hl7.fhir.r5.conformance.profile;
public class BindingResolution {
public BindingResolution(String display, String url) {
this.display = display;
this.url = url;
}
public BindingResolution() {
// TODO Auto-generated constructor stub
}
public String display;
public String url;
}

View File

@ -1,9 +1,10 @@
package org.hl7.fhir.r5.conformance.profile;
import org.hl7.fhir.r5.model.ElementDefinition;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.hl7.fhir.r5.model.ElementDefinition;
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public class PathSlicingParams {

View File

@ -0,0 +1,19 @@
package org.hl7.fhir.r5.conformance.profile;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent;
import org.hl7.fhir.r5.model.StructureDefinition;
public interface ProfileKnowledgeProvider {
boolean isDatatype(String typeSimple);
boolean isPrimitiveType(String typeSimple);
boolean isResource(String typeSimple);
boolean hasLinkFor(String typeSimple);
String getLinkFor(String corePath, String typeSimple);
BindingResolution resolveBinding(StructureDefinition def,
ElementDefinitionBindingComponent binding, String path) throws FHIRException;
BindingResolution resolveBinding(StructureDefinition def, String url, String path) throws FHIRException;
String getLinkForProfile(StructureDefinition profile, String url);
boolean prependLinks();
String getLinkForUrl(String corePath, String s);
}

View File

@ -1,24 +1,26 @@
package org.hl7.fhir.r5.conformance.profile;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.With;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.conformance.ElementRedirection;
import org.hl7.fhir.r5.model.CanonicalType;
import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionSnapshotComponent;
import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.i18n.I18nConstants;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.With;
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class ProfilePathProcessor {
@ -279,7 +281,7 @@ public class ProfilePathProcessor {
throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.NOT_DONE_YET));
}
if (profileUtilities.hasInnerDiffMatches(getDifferential(), currentBasePath, cursors.diffCursor, getDiffLimit(), cursors.base.getElement(), false)) {
if (profileUtilities.baseHasChildren(cursors.base, currentBase)) { // not a new type here
if (baseHasChildren(cursors.base, currentBase)) { // not a new type here
throw new Error("This situation is not yet handled (constrain slicing to 1..1 and fix base slice for inline structure - please report issue to grahame@fhir.org along with a test case that reproduces this error (@ " + currentBasePath + " | " + currentBase.getPath() + ")");
} else {
StructureDefinition dt = profileUtilities.getTypeForElement(getDifferential(), cursors.diffCursor, getProfileName(), diffMatches, outcome, getWebUrl(), getDerived());
@ -689,6 +691,28 @@ public class ProfilePathProcessor {
return res;
}
private int indexOfFirstNonChild(StructureDefinitionSnapshotComponent base, ElementDefinition currentBase, int i, int baseLimit) {
return baseLimit+1;
}
private boolean baseHasChildren(StructureDefinitionSnapshotComponent base, ElementDefinition ed) {
int index = base.getElement().indexOf(ed);
if (index == -1 || index >= base.getElement().size()-1)
return false;
String p = base.getElement().get(index+1).getPath();
return isChildOf(p, ed.getPath());
}
private boolean isChildOf(String sub, String focus) {
if (focus.endsWith("[x]")) {
focus = focus.substring(0, focus.length()-3);
return sub.startsWith(focus);
} else
return sub.startsWith(focus+".");
}
private void processSimplePathWithEmptyDiffMatches(ElementDefinition currentBase, String currentBasePath, List<ElementDefinition> diffMatches, ProfilePathProcessorState cursors) {
ElementDefinition outcome = profileUtilities.updateURLs(getUrl(), getWebUrl(), currentBase.copy());
outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource()));
@ -703,10 +727,10 @@ public class ProfilePathProcessor {
if (profileUtilities.hasInnerDiffMatches(getDifferential(), currentBasePath, cursors.diffCursor, getDiffLimit(), cursors.base.getElement(), true)) {
// well, the profile walks into this, so we need to as well
// did we implicitly step into a new type?
if (profileUtilities.baseHasChildren(cursors.base, currentBase)) { // not a new type here
if (baseHasChildren(cursors.base, currentBase)) { // not a new type here
this.incrementDebugIndent().withSlicing(new PathSlicingParams()). processPaths( new ProfilePathProcessorState(cursors.base, cursors.baseCursor + 1, cursors.diffCursor, cursors.contextName, cursors.resultPathBase));
cursors.baseCursor = profileUtilities.indexOfFirstNonChild(cursors.base, currentBase, cursors.baseCursor + 1, getBaseLimit());
cursors.baseCursor = indexOfFirstNonChild(cursors.base, currentBase, cursors.baseCursor + 1, getBaseLimit());
}
else {
if (outcome.getType().size() == 0 && !outcome.hasContentReference()) {
@ -858,7 +882,7 @@ public class ProfilePathProcessor {
profileUtilities.updateFromDefinition(outcome, diffMatches.get(0), getProfileName(), closed, getUrl(), getSourceStructureDefinition(), getDerived()); // if there's no slice, we don't want to update the unsliced description
profileUtilities.removeStatusExtensions(outcome);
} else if (!diffMatches.get(0).hasSliceName()) {
diffMatches.get(0).setUserData(profileUtilities.GENERATED_IN_SNAPSHOT, outcome); // because of updateFromDefinition isn't called
diffMatches.get(0).setUserData(profileUtilities.UD_GENERATED_IN_SNAPSHOT, outcome); // because of updateFromDefinition isn't called
}
getResult().getElement().add(outcome);
@ -954,8 +978,8 @@ public class ProfilePathProcessor {
outcome.setPath(profileUtilities.fixedPathDest(getContextPathTarget(), outcome.getPath(), getRedirector(), getContextPathSource()));
if (!outcome.getPath().startsWith(cursors.resultPathBase))
throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH));
outcome.setUserData(profileUtilities.BASE_PATH, outcome.getPath());
outcome.setUserData(profileUtilities.BASE_MODEL, getSourceStructureDefinition().getUrl());
outcome.setUserData(profileUtilities.UD_BASE_PATH, outcome.getPath());
outcome.setUserData(profileUtilities.UD_BASE_MODEL, getSourceStructureDefinition().getUrl());
getResult().getElement().add(outcome);
cursors.baseCursor++;
}
@ -1223,13 +1247,13 @@ public class ProfilePathProcessor {
getResult().getElement().add(outcome);
// the profile walks into this, so we need to as well
// did we implicitly step into a new type?
if (profileUtilities.baseHasChildren(cursors.base, currentBase)) { // not a new type here
if (baseHasChildren(cursors.base, currentBase)) { // not a new type here
this
.incrementDebugIndent()
.withSlicing(new PathSlicingParams()).processPaths(
new ProfilePathProcessorState(cursors.base, cursors.baseCursor + 1, cursors.diffCursor, cursors.contextName, cursors.resultPathBase));
cursors.baseCursor = profileUtilities.indexOfFirstNonChild(cursors.base, currentBase, cursors.baseCursor, getBaseLimit());
cursors.baseCursor = indexOfFirstNonChild(cursors.base, currentBase, cursors.baseCursor, getBaseLimit());
} else {
StructureDefinition dt = profileUtilities.getTypeForElement(getDifferential(), cursors.diffCursor, getProfileName(), diffMatches, outcome, getWebUrl(), getDerived());
cursors.contextName = dt.getUrl();
@ -1264,8 +1288,8 @@ public class ProfilePathProcessor {
if (!outcome.getPath().startsWith(cursors.resultPathBase))
throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.ADDING_WRONG_PATH_IN_PROFILE___VS_, getProfileName(), outcome.getPath(), cursors.resultPathBase));
getResult().getElement().add(outcome); // so we just copy it in
outcome.setUserData(profileUtilities.BASE_MODEL, getSourceStructureDefinition().getUrl());
outcome.setUserData(profileUtilities.BASE_PATH, cursors.resultPathBase);
outcome.setUserData(profileUtilities.UD_BASE_MODEL, getSourceStructureDefinition().getUrl());
outcome.setUserData(profileUtilities.UD_BASE_PATH, cursors.resultPathBase);
cursors.baseCursor++;
}
}

View File

@ -1,8 +1,9 @@
package org.hl7.fhir.r5.conformance.profile;
import org.hl7.fhir.r5.model.StructureDefinition;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import org.hl7.fhir.r5.model.StructureDefinition;
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public class ProfilePathProcessorState {

View File

@ -10,8 +10,9 @@ import java.util.Set;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.conformance.profile.BindingResolution;
import org.hl7.fhir.r5.conformance.profile.ProfileKnowledgeProvider;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.ProfileKnowledgeProvider;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.ElementDefinition;

View File

@ -613,5 +613,6 @@ public class Coding extends DataType implements IBaseCoding, ICompositeType, ICo
}
// end addition
}

View File

@ -120,7 +120,7 @@ public class PEBuilder {
if (!profile.hasSnapshot()) {
throw new DefinitionException("Profile '"+profile.getVersionedUrl()+"' does not have a snapshot");
}
return new PEDefinitionResource(this, profile);
return new PEDefinitionResource(this, profile, profile.getName());
}
/**
@ -145,7 +145,7 @@ public class PEBuilder {
if (!profile.hasSnapshot()) {
throw new DefinitionException("Profile '"+url+"' does not have a snapshot");
}
return new PEDefinitionResource(this, profile);
return new PEDefinitionResource(this, profile, profile.getName());
}
/**
@ -170,7 +170,7 @@ public class PEBuilder {
if (!profile.hasSnapshot()) {
throw new DefinitionException("Profile '"+url+"' does not have a snapshot");
}
return new PEDefinitionResource(this, profile);
return new PEDefinitionResource(this, profile, profile.getName());
}
/**
@ -321,7 +321,7 @@ public class PEBuilder {
ElementDefinition defn = list.get(i);
if (!defn.getMax().equals("0") && (allFixed || include(defn))) {
if (passElementPropsCheck(defn) && !Utilities.existsInList(defn.getName(), omitList)) {
PEDefinitionElement pe = new PEDefinitionElement(this, profile, defn);
PEDefinitionElement pe = new PEDefinitionElement(this, profile, defn, parent.path());
pe.setRecursing(definition == defn || (profile.getDerivation() == TypeDerivationRule.SPECIALIZATION && profile.getType().equals("Extension")));
if (cu.isPrimitiveDatatype(definition.getTypeFirstRep().getWorkingCode()) && "value".equals(pe.name())) {
pe.setMustHaveValue(definition.getMustHaveValue());
@ -335,11 +335,11 @@ public class PEBuilder {
while (i < list.size() && list.get(i).getPath().equals(defn.getPath())) {
StructureDefinition ext = getExtensionDefinition(list.get(i));
if (ext != null) {
res.add(new PEDefinitionExtension(this, list.get(i).getSliceName(), profile, list.get(i), defn, ext));
res.add(new PEDefinitionExtension(this, list.get(i).getSliceName(), profile, list.get(i), defn, ext, parent.path()));
} else if (isTypeSlicing(defn)) {
res.add(new PEDefinitionTypeSlice(this, list.get(i).getSliceName(), profile, list.get(i), defn));
res.add(new PEDefinitionTypeSlice(this, list.get(i).getSliceName(), profile, list.get(i), defn, parent.path()));
} else {
res.add(new PEDefinitionSlice(this, list.get(i).getSliceName(), profile, list.get(i), defn));
res.add(new PEDefinitionSlice(this, list.get(i).getSliceName(), profile, list.get(i), defn, parent.path()));
}
i++;
}
@ -363,7 +363,6 @@ public class PEBuilder {
}
}
private boolean passElementPropsCheck(ElementDefinition bdefn) {
switch (elementProps) {
case EXTENSION:
@ -390,14 +389,14 @@ public class PEBuilder {
}
}
protected List<PEDefinition> listSlices(StructureDefinition profileStructure, ElementDefinition definition) {
protected List<PEDefinition> listSlices(StructureDefinition profileStructure, ElementDefinition definition, PEDefinition parent) {
List<ElementDefinition> list = pu.getSliceList(profileStructure, definition);
List<PEDefinition> res = new ArrayList<>();
for (ElementDefinition ed : list) {
if (profileStructure.getDerivation() == TypeDerivationRule.CONSTRAINT && profileStructure.getType().equals("Extension")) {
res.add(new PEDefinitionSubExtension(this, profileStructure, ed));
res.add(new PEDefinitionSubExtension(this, profileStructure, ed, parent.path()));
} else {
PEDefinitionElement pe = new PEDefinitionElement(this, profileStructure, ed);
PEDefinitionElement pe = new PEDefinitionElement(this, profileStructure, ed, parent.path());
pe.setRecursing(definition == ed || (profileStructure.getDerivation() == TypeDerivationRule.SPECIALIZATION && profileStructure.getType().equals("Extension")));
res.add(pe);
}
@ -562,4 +561,8 @@ public class PEBuilder {
public List<Base> exec(Resource resource, Base data, String fhirpath) {
return fpe.evaluate(this, resource, resource, data, fhirpath);
}
public boolean isResource(String name) {
return cu.isResource(name);
}
}

View File

@ -7,14 +7,23 @@ import java.util.Map;
import org.apache.xmlbeans.impl.xb.xsdschema.All;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.r5.context.ContextUtilities;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.profilemodel.PEDefinition.PEDefinitionElementMode;
import org.hl7.fhir.utilities.Utilities;
public abstract class PEDefinition {
public enum PEDefinitionElementMode {
Resource, Element, DataType, Extension
}
protected PEBuilder builder;
protected String name;
protected String path;
protected StructureDefinition profile;
protected ElementDefinition definition;
protected List<PEType> types;
@ -40,11 +49,12 @@ public abstract class PEDefinition {
//// this.data = data;
// }
protected PEDefinition(PEBuilder builder, String name, StructureDefinition profile, ElementDefinition definition) {
protected PEDefinition(PEBuilder builder, String name, StructureDefinition profile, ElementDefinition definition, String ppath) {
this.builder = builder;
this.name = name;
this.profile = profile;
this.definition = definition;
this.path = path == null ? name : ppath+"."+name;
}
@ -55,6 +65,13 @@ public abstract class PEDefinition {
return name;
}
/**
* @return The path of the element or slice in the profile (name.name.name...)
*/
public String path() {
return path;
}
/**
* @return The name of the element in the resource (may be different to the slice name)
*/
@ -239,6 +256,28 @@ public abstract class PEDefinition {
return max() > 1;
}
public PEDefinitionElementMode mode() {
if (builder.isResource(definition.getBase().getPath())) {
return PEDefinitionElementMode.Resource;
}
for (TypeRefComponent tr : definition.getType()) {
if ("Extension".equals(tr.getWorkingCode())) {
return PEDefinitionElementMode.Extension;
}
if (!Utilities.existsInList(tr.getWorkingCode(), "Element", "BackboneElement")) {
return PEDefinitionElementMode.DataType;
}
}
return PEDefinitionElementMode.Element;
}
/**
* @return true if this element is profiled one way or another
*/
public boolean isProfiled() {
return !profile.getUrl().startsWith("http://hl7.org/fhir/StructureDefinition");
}
}

View File

@ -10,8 +10,8 @@ import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
public class PEDefinitionElement extends PEDefinition {
public PEDefinitionElement(PEBuilder builder, StructureDefinition profile, ElementDefinition definition) {
super(builder, definition.getName(), profile, definition);
public PEDefinitionElement(PEBuilder builder, StructureDefinition profile, ElementDefinition definition, String ppath) {
super(builder, definition.getName(), profile, definition, ppath);
}
@Override
@ -38,7 +38,7 @@ public class PEDefinitionElement extends PEDefinition {
if (definition.hasSlicing()) {
// get all the slices
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(" or ");
List<PEDefinition> slices = builder.listSlices(profile, definition);
List<PEDefinition> slices = builder.listSlices(profile, definition, this);
// list all the fhirpaths
for (PEDefinition slice : slices) {
b.append("("+builder.makeSliceExpression(profile, definition.getSlicing(), slice.definition())+")");
@ -52,4 +52,5 @@ public class PEDefinitionElement extends PEDefinition {
}
}
}

View File

@ -6,6 +6,8 @@ import org.hl7.fhir.r5.model.CanonicalType;
import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.ElementDefinition.SlicingRules;
import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent;
import org.hl7.fhir.r5.profilemodel.PEDefinition.PEDefinitionElementMode;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.r5.model.StructureDefinition;
public class PEDefinitionExtension extends PEDefinition {
@ -15,8 +17,8 @@ public class PEDefinitionExtension extends PEDefinition {
private ElementDefinition eed;
private ElementDefinition ved;
public PEDefinitionExtension(PEBuilder builder, String name, StructureDefinition profile, ElementDefinition definition, ElementDefinition sliceDefinition, StructureDefinition extension) {
super(builder, name, profile, definition);
public PEDefinitionExtension(PEBuilder builder, String name, StructureDefinition profile, ElementDefinition definition, ElementDefinition sliceDefinition, StructureDefinition extension, String ppath) {
super(builder, name, profile, definition, ppath);
this.sliceDefinition = sliceDefinition;
this.extension= extension;
eed = extension.getSnapshot().getElementByPath("Extension.extension");
@ -48,7 +50,7 @@ public class PEDefinitionExtension extends PEDefinition {
if (eed.getSlicing().getRules() != SlicingRules.CLOSED) {
children.addAll(builder.listChildren(allFixed, this, extension, eed, "http://hl7.org/fhir/StructureDefinition/Extension", "value[x]", "url"));
}
children.addAll(builder.listSlices(extension, eed));
children.addAll(builder.listSlices(extension, eed, this));
}
}
@ -61,4 +63,7 @@ public class PEDefinitionExtension extends PEDefinition {
}
}
public PEDefinitionElementMode mode() {
return PEDefinitionElementMode.Extension;
}
}

View File

@ -6,8 +6,8 @@ import org.hl7.fhir.r5.model.StructureDefinition;
public class PEDefinitionResource extends PEDefinition {
public PEDefinitionResource(PEBuilder builder, StructureDefinition profile) {
super(builder, profile.getName(), profile, profile.getSnapshot().getElementFirstRep());
public PEDefinitionResource(PEBuilder builder, StructureDefinition profile, String ppath) {
super(builder, profile.getName(), profile, profile.getSnapshot().getElementFirstRep(), ppath);
}
@Override

View File

@ -11,8 +11,8 @@ public class PEDefinitionSlice extends PEDefinition {
protected ElementDefinition sliceDefinition;
public PEDefinitionSlice(PEBuilder builder, String name, StructureDefinition profile, ElementDefinition profileDefinition, ElementDefinition sliceDefinition) {
super(builder, name, profile, profileDefinition);
public PEDefinitionSlice(PEBuilder builder, String name, StructureDefinition profile, ElementDefinition profileDefinition, ElementDefinition sliceDefinition, String ppath) {
super(builder, name, profile, profileDefinition, ppath);
this.sliceDefinition = sliceDefinition;
}

View File

@ -6,6 +6,7 @@ import org.hl7.fhir.r5.model.CanonicalType;
import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.ElementDefinition.SlicingRules;
import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent;
import org.hl7.fhir.r5.profilemodel.PEDefinition.PEDefinitionElementMode;
import org.hl7.fhir.r5.model.StructureDefinition;
public class PEDefinitionSubExtension extends PEDefinition {
@ -14,8 +15,8 @@ public class PEDefinitionSubExtension extends PEDefinition {
private ElementDefinition ved;
private ElementDefinition ued;
public PEDefinitionSubExtension(PEBuilder builder, StructureDefinition profile, ElementDefinition definition) {
super(builder, definition.getSliceName(), profile, definition);
public PEDefinitionSubExtension(PEBuilder builder, StructureDefinition profile, ElementDefinition definition, String ppath) {
super(builder, definition.getSliceName(), profile, definition, ppath);
List<ElementDefinition> childDefs = builder.getChildren(profile, definition);
eed = getElementByName(childDefs, "extension");
ved = getElementByName(childDefs, "value[x]");
@ -56,7 +57,7 @@ public class PEDefinitionSubExtension extends PEDefinition {
if (eed.getSlicing().getRules() != SlicingRules.CLOSED) {
children.addAll(builder.listChildren(allFixed, this, profile, eed, "http://hl7.org/fhir/StructureDefinition/Extension", "value[x]", "url"));
}
children.addAll(builder.listSlices(profile, eed));
children.addAll(builder.listSlices(profile, eed, this));
}
}
@ -65,8 +66,12 @@ public class PEDefinitionSubExtension extends PEDefinition {
if (ved.isRequired() || eed.isProhibited()) {
return "extension('"+ued.getFixed().primitiveValue()+"').value";
} else {
return "extension('"+ued.getFixed().primitiveValue()+"').extension";
return "extension('"+ued.getFixed().primitiveValue()+"')";
}
}
public PEDefinitionElementMode mode() {
return PEDefinitionElementMode.Extension;
}
}

View File

@ -12,8 +12,8 @@ public class PEDefinitionTypeSlice extends PEDefinition {
protected ElementDefinition sliceDefinition;
public PEDefinitionTypeSlice(PEBuilder builder, String name, StructureDefinition profile, ElementDefinition definition, ElementDefinition sliceDefinition) {
super(builder, name, profile, definition);
public PEDefinitionTypeSlice(PEBuilder builder, String name, StructureDefinition profile, ElementDefinition definition, ElementDefinition sliceDefinition, String ppath) {
super(builder, name, profile, definition, ppath);
this.sliceDefinition = sliceDefinition;
}

View File

@ -236,4 +236,8 @@ public class PEInstance {
public String getPath() {
return path;
}
public Base getBase() {
return data;
}
}

View File

@ -1,17 +1,32 @@
package org.hl7.fhir.r5.profilemodel.gen;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.profilemodel.PEInstance;
public class PEGeneratedBase {
protected PEInstance instance;
protected void removeChild(String string) {
PEInstance child = instance.child("simple");
protected void removeChild(String name) {
PEInstance child = instance.child(name);
if (child != null) {
instance.removeChild(child);
}
}
protected void removeChildren(String name) {
for (PEInstance child : instance.children(name)) {
instance.removeChild(child);
}
}
public PEInstance getInstance() {
return instance;
}
public Base getData() {
return instance.getBase();
}
}

View File

@ -1,5 +1,8 @@
package org.hl7.fhir.r5.profilemodel.gen;
import java.util.ArrayList;
import java.util.List;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.model.CodeType;
import org.hl7.fhir.r5.model.CodeableConcept;
@ -60,37 +63,103 @@ public class ProfileExample extends PEGeneratedBase {
}
}
public static class ProfileExampleComplexSlice3 extends PEGeneratedBase {
private ProfileExampleComplexSlice3(PEInstance instance) {
super();
this.instance = instance;
}
public List<Coding> getSlice3a() {
List<Coding> res = new ArrayList<>();
for (PEInstance pe : instance.children("slice3a")) {
res.add((Coding) pe.asDataType());
}
return res;
}
public boolean hasSlice3a() {
return instance.children("slice3a").size() > 0;
}
public ProfileExampleComplexSlice3 clearSlice3a() {
removeChildren("slice3a");
return this;
}
public List<StringType> getSlice3b() {
List<StringType> res = new ArrayList<>();
for (PEInstance pe : instance.children("slice3b")) {
res.add((StringType) pe.asDataType());
}
return res;
}
public boolean hasSlice3b() {
return instance.children("slice3b").size() > 0;
}
public ProfileExampleComplexSlice3 clearSlice3b() {
removeChildren("slice3b");
return this;
}
}
public static class ProfileExampleComplex extends PEGeneratedBase {
private ProfileExampleComplex(PEInstance instance) {
super();
this.instance = instance;
}
public Coding getSlice1() {
return (Coding) instance.forceChild("slice1").asDataType();
public List<Coding> getSlice1() {
List<Coding> res = new ArrayList<>();
for (PEInstance pe : instance.children("slice1")) {
res.add((Coding) pe.asDataType());
}
return res;
}
public boolean hasSlice1() {
return instance.child("slice1") != null;
return instance.children("slice1").size() > 0;
}
public ProfileExampleComplex clearSlice1() {
removeChild("slice1x`");
removeChildren("slice1");
return this;
}
public StringType getSlice2() {
return (StringType) instance.forceChild("slice2").asDataType();
public List<StringType> getSlice2() {
List<StringType> res = new ArrayList<>();
for (PEInstance pe : instance.children("slice2")) {
res.add((StringType) pe.asDataType());
}
return res;
}
public boolean hasSlice2() {
return instance.child("slice1") != null;
return instance.children("slice2").size() > 0;
}
public ProfileExampleComplex clearSlice2() {
removeChild("slice1");
removeChildren("slice1");
return this;
}
public ProfileExampleComplexSlice3 getSlice3() {
PEInstance pe = instance.forceChild("slice3");
return new ProfileExampleComplexSlice3(pe);
}
public boolean hasComplex() {
return instance.child("slice3") != null;
}
public ProfileExampleComplex clearComplex() {
removeChild("slice3");
return this;
}
}
public ProfileExample(IWorkerContext context, Observation observation) {

View File

@ -0,0 +1,47 @@
package org.hl7.fhir.r5.renderers;
import org.hl7.fhir.r5.model.CodeableConcept;
import org.hl7.fhir.r5.model.Coding;
public interface CodeResolver {
public class CodeResolution {
private String systenName;
private String systemLink;
private String link;
private String display;
private String hint;
protected CodeResolution(String systenName, String systemLink, String link, String display, String hint) {
super();
this.systenName = systenName;
this.systemLink = systemLink;
this.link = link;
this.display = display;
this.hint = hint;
}
public String getSystenName() {
return systenName;
}
public String getSystemLink() {
return systemLink;
}
public String getLink() {
return link;
}
public String getDisplay() {
return display;
}
public String getHint() {
return hint;
}
}
public CodeResolution resolveCode(String system, String code);
public CodeResolution resolveCode(Coding code);
public CodeResolution resolveCode(CodeableConcept code);
}

View File

@ -15,7 +15,6 @@ import java.time.format.FormatStyle;
import java.time.format.SignStyle;
import java.util.Currency;
import java.util.List;
import java.util.Set;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
@ -71,9 +70,11 @@ import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent;
import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceDesignationComponent;
import org.hl7.fhir.r5.renderers.utils.BaseWrappers.BaseWrapper;
import org.hl7.fhir.r5.renderers.CodeResolver.CodeResolution;
import org.hl7.fhir.r5.renderers.utils.RenderingContext;
import org.hl7.fhir.r5.renderers.utils.RenderingContext.GenerationRules;
import org.hl7.fhir.r5.renderers.utils.RenderingContext.ResourceRendererMode;
import org.hl7.fhir.r5.terminologies.JurisdictionUtilities;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
@ -85,7 +86,7 @@ import org.hl7.fhir.utilities.xhtml.XhtmlParser;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
public class DataRenderer extends Renderer {
public class DataRenderer extends Renderer implements CodeResolver {
// -- 1. context --------------------------------------------------------------
@ -302,6 +303,9 @@ public class DataRenderer extends Renderer {
}
private String lookupCode(String system, String version, String code) {
if (JurisdictionUtilities.isJurisdiction(system)) {
return JurisdictionUtilities.displayJurisdiction(system+"#"+code);
}
ValidationResult t = getContext().getWorker().validateCode(getContext().getTerminologyServiceOptions().setVersionFlexible(true), system, version, code, null);
if (t != null && t.getDisplay() != null)
@ -948,6 +952,12 @@ public class DataRenderer extends Renderer {
} else {
return "https://www.nlm.nih.gov/research/umls/rxnorm/index.html";
}
} else if ("urn:iso:std:iso:3166".equals(system)) {
if (!Utilities.noString(code)) {
return "https://en.wikipedia.org/wiki/ISO_3166-2:"+code;
} else {
return "https://en.wikipedia.org/wiki/ISO_3166-2";
}
} else {
CodeSystem cs = context.getWorker().fetchCodeSystem(system, version);
if (cs != null && cs.hasUserData("path")) {
@ -961,6 +971,41 @@ public class DataRenderer extends Renderer {
return null;
}
public CodeResolution resolveCode(String system, String code) {
return resolveCode(new Coding().setSystem(system).setCode(code));
}
public CodeResolution resolveCode(Coding c) {
String systemName;
String systemLink;
String link;
String display = null;
String hint;
if (c.hasDisplayElement())
display = c.getDisplay();
if (Utilities.noString(display))
display = lookupCode(c.getSystem(), c.getVersion(), c.getCode());
if (Utilities.noString(display)) {
display = c.getCode();
}
CodeSystem cs = context.getWorker().fetchCodeSystem(c.getSystem());
systemLink = cs != null ? cs.getUserString("path") : null;
systemName = cs != null ? cs.present() : describeSystem(c.getSystem());
link = getLinkForCode(c.getSystem(), c.getVersion(), c.getCode());
hint = systemName+": "+display+(c.hasVersion() ? " (version = "+c.getVersion()+")" : "");
return new CodeResolution(systemName, systemLink, link, display, hint);
}
public CodeResolution resolveCode(CodeableConcept code) {
if (code.hasCoding()) {
return resolveCode(code.getCodingFirstRep());
} else {
return new CodeResolution(null, null, null, code.getText(), code.getText());
}
}
protected void renderCodingWithDetails(XhtmlNode x, Coding c) {
String s = "";
if (c.hasDisplayElement())

View File

@ -4,6 +4,7 @@ import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.renderers.utils.RenderingContext;
import org.hl7.fhir.r5.renderers.utils.RenderingContext.GenerationRules;
import org.hl7.fhir.r5.renderers.utils.RenderingContext.ResourceRendererMode;
import org.hl7.fhir.r5.utils.TranslatingUtilities;
import org.hl7.fhir.utilities.MarkDownProcessor;
import org.hl7.fhir.utilities.MarkDownProcessor.Dialect;
import org.hl7.fhir.utilities.validation.ValidationOptions;
@ -25,7 +26,7 @@ import org.hl7.fhir.utilities.validation.ValidationOptions;
* @author graha
*
*/
public class Renderer {
public class Renderer extends TranslatingUtilities {
protected RenderingContext context;

View File

@ -4,7 +4,6 @@ import org.hl7.fhir.r5.model.DomainResource;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper;
import org.hl7.fhir.r5.renderers.utils.RenderingContext;
import org.hl7.fhir.r5.renderers.utils.RenderingContext.GenerationRules;
import org.hl7.fhir.r5.renderers.utils.Resolver.ResourceContext;
import org.hl7.fhir.utilities.Utilities;

View File

@ -2,11 +2,9 @@ package org.hl7.fhir.r5.renderers;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.context.ContextUtilities;
import org.hl7.fhir.r5.model.ActorDefinition;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.CanonicalType;

View File

@ -11,8 +11,8 @@ import java.util.Map;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.conformance.profile.ProfileKnowledgeProvider;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.ProfileKnowledgeProvider;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.model.Base;
@ -74,6 +74,12 @@ public class RenderingContext {
IG_PUBLISHER
}
public enum StructureDefinitionRendererMode {
SUMMARY, // 5 cells: tree/name | flags | cardinality | type | details
BINDINGS, // tree/name + column for each kind of binding found, cells are lists of bindings
OBLIGATIONS, // tree/name + column for each actor that has obligations
}
public enum QuestionnaireRendererMode {
/**
* A visual presentation of the questionnaire, with a set of property panes that can be toggled on and off.
@ -139,6 +145,8 @@ public class RenderingContext {
private boolean inlineGraphics;
private QuestionnaireRendererMode questionnaireMode = QuestionnaireRendererMode.FORM;
private StructureDefinitionRendererMode structureMode = StructureDefinitionRendererMode.SUMMARY;
private boolean addGeneratedNarrativeHeader = true;
private boolean showComments = false;
@ -201,6 +209,7 @@ public class RenderingContext {
res.destDir = destDir;
res.addGeneratedNarrativeHeader = addGeneratedNarrativeHeader;
res.questionnaireMode = questionnaireMode;
res.structureMode = structureMode;
res.header = header;
res.links.putAll(links);
res.inlineGraphics = inlineGraphics;
@ -356,6 +365,9 @@ public class RenderingContext {
public RenderingContext setProfileUtilities(ProfileUtilities profileUtilities) {
this.profileUtilitiesR = profileUtilities;
if (pkp == null && profileUtilities.getPkp() != null) {
pkp = profileUtilities.getPkp();
}
return this;
}
@ -433,6 +445,15 @@ public class RenderingContext {
return this;
}
public StructureDefinitionRendererMode getStructureMode() {
return structureMode;
}
public RenderingContext setStructureMode(StructureDefinitionRendererMode structureMode) {
this.structureMode = structureMode;
return this;
}
public String fixReference(String ref) {
if (!Utilities.isAbsoluteUrl(ref)) {
return (localPrefix == null ? "" : localPrefix)+ref;

View File

@ -5996,5 +5996,9 @@ public class JurisdictionUtilities {
}
return "Unknown region code '"+c.getCode()+"'";
}
public static boolean isJurisdiction(String system) {
return Utilities.existsInList(system, "http://unstats.un.org/unsd/methods/m49/m49.htm", "urn:iso:std:iso:3166", "urn:iso:std:iso:3166:-2");
}
}

View File

@ -39,7 +39,7 @@ public class TestPackageLoader implements IContextResourceLoader {
@Override
public String getResourcePath(Resource resource) {
return null;
return resource.fhirType().toLowerCase()+"-"+resource.getId()+".html";
}
@Override

View File

@ -36,8 +36,8 @@ package org.hl7.fhir.r5.utils.structuremap;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.conformance.profile.ProfileKnowledgeProvider;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.ProfileKnowledgeProvider;
import org.hl7.fhir.r5.context.ContextUtilities;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.context.IWorkerContext.ValidationResult;

View File

@ -16,6 +16,7 @@ import org.hl7.fhir.r5.profilemodel.PEType;
import org.hl7.fhir.r5.profilemodel.gen.ProfileExample;
import org.hl7.fhir.r5.profilemodel.gen.ProfileExample.LOINCCodesForCholesterolInSerumPlasma;
import org.hl7.fhir.r5.profilemodel.gen.ProfileExample.ProfileExampleComplex;
import org.hl7.fhir.r5.profilemodel.gen.ProfileExample.ProfileExampleComplexSlice3;
import org.hl7.fhir.r5.profilemodel.PEBuilder;
import org.hl7.fhir.r5.profilemodel.PEBuilder.PEElementPropertiesPolicy;
import org.hl7.fhir.r5.profilemodel.PEInstance.PEInstanceDataKind;
@ -105,7 +106,7 @@ public class PETests {
checkElement(gchildren.get(0), "extension", "extension", 0, Integer.MAX_VALUE, false, "http://hl7.org/fhir/StructureDefinition/Extension", 3, "extension");
checkElement(gchildren.get(1), "extension", "slice1", 0, 2, false, "http://hl7.org/fhir/StructureDefinition/Coding", 6, "extension('slice1').value");
checkElement(gchildren.get(2), "extension", "slice2", 0, Integer.MAX_VALUE, false, "http://hl7.org/fhir/StructureDefinition/string", 2, "extension('slice2').value");
checkElement(gchildren.get(3), "extension", "slice3", 1, 1, false, "http://hl7.org/fhir/StructureDefinition/Extension", 3, "extension('slice3').extension");
checkElement(gchildren.get(3), "extension", "slice3", 1, 1, false, "http://hl7.org/fhir/StructureDefinition/Extension", 3, "extension('slice3')");
ggchildren = gchildren.get(3).children("http://hl7.org/fhir/StructureDefinition/Extension");
checkElement(ggchildren.get(0), "extension", "extension", 0, Integer.MAX_VALUE, false, "http://hl7.org/fhir/StructureDefinition/Extension", 3, "extension");
@ -351,14 +352,21 @@ public class PETests {
Assertions.assertEquals(PEInstanceDataKind.Primitive, slice2.getDataKind());
Assertions.assertEquals("A string value", slice2.getPrimitiveAsString());
PEInstance slice3 = complex.child("slice3");
Assertions.assertNotNull(slice3);
Assertions.assertEquals("TestProfile.complex.slice3", slice3.getPath());
ProfileExample ex = new ProfileExample(obs);
Assertions.assertEquals(ObservationStatus.FINAL, ex.getStatus());
Assertions.assertEquals("76690-7", ex.getCode().getCodingFirstRep().getCode());
Assertions.assertEquals(LOINCCodesForCholesterolInSerumPlasma.L14647_2, ex.getSimple());
ProfileExampleComplex cplx = ex.getComplex();
Assertions.assertNotNull(cplx);
Assertions.assertEquals("18767-4", cplx.getSlice1().getCode());
Assertions.assertEquals("A string value", cplx.getSlice2().primitiveValue());
Assertions.assertEquals("18767-4", cplx.getSlice1().get(0).getCode());
Assertions.assertEquals("A string value", cplx.getSlice2().get(0).primitiveValue());
ProfileExampleComplexSlice3 sl3 = cplx.getSlice3();
Assertions.assertEquals("56874-1", sl3.getSlice3a().get(0).getCode());
Assertions.assertEquals("Another string value", sl3.getSlice3b().get(0).primitiveValue());
}

View File

@ -11,8 +11,9 @@ import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.lang3.NotImplementedException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.conformance.profile.BindingResolution;
import org.hl7.fhir.r5.conformance.profile.ProfileKnowledgeProvider;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.ProfileKnowledgeProvider;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.elementmodel.Manager;
import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat;
@ -22,17 +23,22 @@ import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.renderers.RendererFactory;
import org.hl7.fhir.r5.renderers.utils.ElementWrappers;
import org.hl7.fhir.r5.renderers.utils.RenderingContext;
import org.hl7.fhir.r5.renderers.utils.RenderingContext.GenerationRules;
import org.hl7.fhir.r5.renderers.utils.RenderingContext.ITypeParser;
import org.hl7.fhir.r5.renderers.utils.RenderingContext.ResourceRendererMode;
import org.hl7.fhir.r5.renderers.utils.RenderingContext.StructureDefinitionRendererMode;
import org.hl7.fhir.r5.test.utils.CompareUtilities;
import org.hl7.fhir.r5.test.utils.TestPackageLoader;
import org.hl7.fhir.r5.test.utils.TestingUtilities;
import org.hl7.fhir.utilities.TerminologyServiceOptions;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
import org.hl7.fhir.utilities.npm.NpmPackage;
import org.hl7.fhir.utilities.xhtml.XhtmlComposer;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
import org.hl7.fhir.utilities.xml.XMLUtil;
@ -86,6 +92,14 @@ public class NarrativeGenerationTests {
@Override
public BindingResolution resolveBinding(StructureDefinition def, String url, String path) throws FHIRException {
ValueSet vs = context.fetchResource(ValueSet.class, url);
if (vs != null) {
if (vs.hasUserData("path")) {
return new BindingResolution(vs.present(), vs.getUserString("path"));
} else {
return new BindingResolution(vs.present(), "valueset-"+vs.getIdBase()+".html");
}
}
throw new NotImplementedException();
}
@ -99,7 +113,7 @@ public class NarrativeGenerationTests {
@Override
public boolean prependLinks() {
throw new NotImplementedException();
return false;
}
@Override
@ -137,13 +151,23 @@ public class NarrativeGenerationTests {
public static class TestDetails {
private String id;
private String sdmode;
private boolean header;
private boolean meta;
private boolean technical;
private String register;
public TestDetails(Element test) {
super();
id = test.getAttribute("id");
sdmode = test.getAttribute("sdmode");
if ("".equals(sdmode)) {
sdmode = null;
}
register = test.getAttribute("register");
if ("".equals(register)) {
register = null;
}
header = "true".equals(test.getAttribute("header"));
meta = "true".equals(test.getAttribute("meta"));
technical = "technical".equals(test.getAttribute("mode"));
@ -153,6 +177,10 @@ public class NarrativeGenerationTests {
return id;
}
public String getSDMode() {
return sdmode;
}
public boolean isHeader() {
return header;
}
@ -161,6 +189,10 @@ public class NarrativeGenerationTests {
return meta;
}
public String getRegister() {
return register;
}
}
public static Stream<Arguments> data() throws ParserConfigurationException, IOException, FHIRFormatError, SAXException {
@ -176,13 +208,23 @@ public class NarrativeGenerationTests {
}
@BeforeAll
public static void setUp() {
public static void setUp() throws IOException {
context = TestingUtilities.getSharedWorkerContext("5.0.0");
FilesystemPackageCacheManager pcm = new FilesystemPackageCacheManager(true);
NpmPackage ips = pcm.loadPackage("hl7.fhir.uv.ips#1.1.0");
context.loadFromPackage(ips, new TestPackageLoader(new String[] { "StructureDefinition", "ValueSet" }));
}
@ParameterizedTest(name = "{index}: file {0}")
@MethodSource("data")
public void test(String id, TestDetails test) throws Exception {
if (test.getRegister() != null) {
if (test.getRegister().endsWith(".json")) {
context.cacheResource(new JsonParser().parse(TestingUtilities.loadTestResourceStream("r5", "narrative", test.getRegister())));
} else {
context.cacheResource(new XmlParser().parse(TestingUtilities.loadTestResourceStream("r5", "narrative", test.getRegister())));
}
}
RenderingContext rc = new RenderingContext(context, null, null, "http://hl7.org/fhir", "", null, ResourceRendererMode.END_USER, GenerationRules.VALID_RESOURCE);
rc.setDestDir(Utilities.path("[tmp]", "narrative"));
rc.setHeader(test.isHeader());
@ -198,6 +240,9 @@ public class NarrativeGenerationTests {
rc.setMode(test.technical ? ResourceRendererMode.TECHNICAL : ResourceRendererMode.END_USER);
rc.setProfileUtilities(new ProfileUtilities(rc.getContext(), null, new TestProfileKnowledgeProvider(rc.getContext())));
if (test.getSDMode() != null) {
rc.setStructureMode(StructureDefinitionRendererMode.valueOf(test.getSDMode().toUpperCase()));
}
Resource source;
if (TestingUtilities.findTestResource("r5", "narrative", test.getId() + ".json")) {
@ -208,7 +253,7 @@ public class NarrativeGenerationTests {
XhtmlNode x = RendererFactory.factory(source, rc).build(source);
String expected = TextFile.streamToString(TestingUtilities.loadTestResourceStream("r5", "narrative", test.getId() + ".html"));
String actual = HEADER+new XhtmlComposer(true, true).compose(x)+FOOTER;
String actual = HEADER+new XhtmlComposer(true, false).compose(x)+FOOTER;
String expectedFileName = CompareUtilities.tempFile("narrative", test.getId() + ".expected.html");
String actualFileName = CompareUtilities.tempFile("narrative", test.getId() + ".actual.html");
TextFile.stringToFile(expected, expectedFileName);

View File

@ -17,8 +17,9 @@ import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.exceptions.PathEngineException;
import org.hl7.fhir.r5.DiffUtils;
import org.hl7.fhir.r5.conformance.profile.BindingResolution;
import org.hl7.fhir.r5.conformance.profile.ProfileKnowledgeProvider;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.ProfileKnowledgeProvider;
import org.hl7.fhir.r5.test.utils.TestPackageLoader;
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
import org.hl7.fhir.r5.formats.JsonParser;

View File

@ -0,0 +1,11 @@
-------------------------------------------------------------------------------------
{"code" : {
"system" : "urn:iso:std:iso:3166",
"code" : "BE"
}, "valueSet" :null, "lang":"en-US", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "versionFlexible":"true"}####
v: {
"severity" : "error",
"error" : "Local Error: Resolved system urn:iso:std:iso:3166 (v1.0.0), but the definition is not complete. Server Error: Attempt to use Terminology server when no Terminology server is available",
"class" : "SERVER_ERROR"
}
-------------------------------------------------------------------------------------

View File

@ -134,7 +134,7 @@ public class HierarchicalTableGenerator extends TranslatingUtilities {
private String hint;
private String style;
private Map<String, String> attributes;
private List<XhtmlNode> children;
private XhtmlNodeList children;
public Piece(String tag) {
super();
@ -205,9 +205,9 @@ public class HierarchicalTableGenerator extends TranslatingUtilities {
return children != null && !children.isEmpty();
}
public List<XhtmlNode> getChildren() {
public XhtmlNodeList getChildren() {
if (children == null)
children = new ArrayList<XhtmlNode>();
children = new XhtmlNodeList();
return children;
}
@ -853,8 +853,9 @@ public class HierarchicalTableGenerator extends TranslatingUtilities {
} else if (p.getStyle() != null) {
XhtmlNode s = addStyle(tc.addTag("span"), p);
s.addText(p.getText());
} else
} else {
tc.addText(p.getText());
}
if (p.hasChildren()) {
tc.getChildNodes().addAll(p.getChildren());
}

View File

@ -0,0 +1,195 @@
package org.hl7.fhir.utilities.xhtml;
import java.io.IOException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.utilities.MarkDownProcessor;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.MarkDownProcessor.Dialect;
public abstract class XhtmlFluent {
protected abstract XhtmlNode addTag(String string);
protected abstract XhtmlNode addText(String cnt);
protected abstract void addChildren(XhtmlNodeList childNodes);
public XhtmlNode h1() {
return addTag("h1");
}
public XhtmlNode h2() {
return addTag("h2");
}
public XhtmlNode h(int level) {
if (level < 1 || level > 6) {
throw new FHIRException("Illegal Header level "+level);
}
return addTag("h"+Integer.toString(level));
}
public XhtmlNode h3() {
return addTag("h3");
}
public XhtmlNode h4() {
return addTag("h4");
}
public XhtmlNode table(String clss) {
XhtmlNode res = addTag("table");
if (!Utilities.noString(clss))
res.setAttribute("class", clss);
return res;
}
public XhtmlNode tr() {
return addTag("tr");
}
public XhtmlNode th() {
return addTag("th");
}
public XhtmlNode td() {
return addTag("td");
}
public XhtmlNode td(String clss) {
return addTag("td").attribute("class", clss);
}
public XhtmlNode div() {
return addTag("div");
}
public XhtmlNode para() {
return addTag("p");
}
public XhtmlNode pre() {
return addTag("pre");
}
public XhtmlNode pre(String clss) {
return addTag("pre").setAttribute("class", clss);
}
public void br() {
addTag("br");
}
public void hr() {
addTag("hr");
}
public XhtmlNode ul() {
return addTag("ul");
}
public XhtmlNode li() {
return addTag("li");
}
public XhtmlNode b() {
return addTag("b");
}
public XhtmlNode i() {
return addTag("i");
}
public XhtmlNode tx(String cnt) {
return addText(cnt);
}
public XhtmlNode tx(int cnt) {
return addText(Integer.toString(cnt));
}
public XhtmlNode ah(String href) {
return addTag("a").attribute("href", href);
}
public XhtmlNode ah(String href, String title) {
XhtmlNode x = addTag("a").attribute("href", href);
if (title != null) {
x.attribute("title", title);
}
return x;
}
public XhtmlNode img(String src, String alt) {
return addTag("img").attribute("src", src).attribute("alt", alt);
}
public XhtmlNode img(String src, String alt, String title) {
return addTag("img").attribute("src", src).attribute("alt", alt).attribute("title", title);
}
public XhtmlNode an(String href) {
return an(href, " ");
}
public XhtmlNode an(String href, String tx) {
XhtmlNode a = addTag("a").attribute("name", href);
a.tx(tx);
return a;
}
public XhtmlNode span(String style, String title) {
XhtmlNode res = addTag("span");
if (!Utilities.noString(style))
res.attribute("style", style);
if (!Utilities.noString(title))
res.attribute("title", title);
return res;
}
public XhtmlNode code(String text) {
return addTag("code").tx(text);
}
public XhtmlNode code() {
return addTag("code");
}
public XhtmlNode blockquote() {
return addTag("blockquote");
}
public void markdown(String md, String source) throws IOException {
if (md != null) {
String s = new MarkDownProcessor(Dialect.COMMON_MARK).process(md, source);
XhtmlParser p = new XhtmlParser();
XhtmlNode m;
try {
m = p.parse("<div>"+s+"</div>", "div");
} catch (org.hl7.fhir.exceptions.FHIRFormatError e) {
throw new FHIRFormatError(e.getMessage(), e);
}
addChildren(m.getChildNodes());
}
}
public void innerHTML(String html) throws IOException {
if (html != null) {
XhtmlParser p = new XhtmlParser();
XhtmlNode m;
try {
m = p.parse("<div>"+html+"</div>", "div");
} catch (org.hl7.fhir.exceptions.FHIRFormatError e) {
throw new FHIRFormatError(e.getMessage(), e);
}
addChildren(m.getChildNodes());
}
}
}

View File

@ -35,7 +35,6 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -50,7 +49,7 @@ import org.hl7.fhir.utilities.Utilities;
import ca.uhn.fhir.model.primitive.XhtmlDt;
@ca.uhn.fhir.model.api.annotation.DatatypeDef(name="xhtml")
public class XhtmlNode implements IBaseXhtml {
public class XhtmlNode extends XhtmlFluent implements IBaseXhtml {
private static final long serialVersionUID = -4362547161441436492L;
@ -83,11 +82,9 @@ public class XhtmlNode implements IBaseXhtml {
private NodeType nodeType;
private String name;
private Map<String, String> attributes = new HashMap<String, String>();
private List<XhtmlNode> childNodes = new ArrayList<XhtmlNode>();
private XhtmlNodeList childNodes = new XhtmlNodeList();
private String content;
private boolean notPretty;
private boolean inPara;
private boolean inLink;
private boolean seperated;
private Boolean emptyExpanded;
@ -129,7 +126,7 @@ public class XhtmlNode implements IBaseXhtml {
return attributes;
}
public List<XhtmlNode> getChildNodes() {
public XhtmlNodeList getChildNodes() {
return childNodes;
}
@ -205,11 +202,11 @@ public class XhtmlNode implements IBaseXhtml {
// }
XhtmlNode node = new XhtmlNode(NodeType.Element);
node.setName(name);
if (inPara || name.equals("p")) {
node.inPara = true;
if (childNodes.isInPara() || name.equals("p")) {
node.getChildNodes().setInPara(true);
}
if (inLink || name.equals("a")) {
node.inLink = true;
if (childNodes.isInLink() || name.equals("a")) {
node.getChildNodes().setInLink(true);
}
childNodes.add(node);
return node;
@ -221,11 +218,11 @@ public class XhtmlNode implements IBaseXhtml {
if (!(nodeType == NodeType.Element || nodeType == NodeType.Document))
throw new Error("Wrong node type. is "+nodeType.toString());
XhtmlNode node = new XhtmlNode(NodeType.Element);
if (inPara || name.equals("p")) {
node.inPara = true;
if (childNodes.isInPara() || name.equals("p")) {
node.getChildNodes().setInPara(true);
}
if (inLink || name.equals("a")) {
node.inLink = true;
if (childNodes.isInLink() || name.equals("a")) {
node.getChildNodes().setInLink(true);
}
node.setName(name);
childNodes.add(index, node);
@ -554,158 +551,6 @@ public class XhtmlNode implements IBaseXhtml {
}
// xhtml easy adders -----------------------------------------------
public XhtmlNode h1() {
return addTag("h1");
}
public XhtmlNode h2() {
return addTag("h2");
}
public XhtmlNode h(int level) {
if (level < 1 || level > 6) {
throw new FHIRException("Illegal Header level "+level);
}
return addTag("h"+Integer.toString(level));
}
public XhtmlNode h3() {
return addTag("h3");
}
public XhtmlNode h4() {
return addTag("h4");
}
public XhtmlNode table(String clss) {
XhtmlNode res = addTag("table");
if (!Utilities.noString(clss))
res.setAttribute("class", clss);
return res;
}
public XhtmlNode tr() {
return addTag("tr");
}
public XhtmlNode th() {
return addTag("th");
}
public XhtmlNode td() {
return addTag("td");
}
public XhtmlNode td(String clss) {
return addTag("td").attribute("class", clss);
}
public XhtmlNode colspan(String n) {
return setAttribute("colspan", n);
}
public XhtmlNode div() {
return addTag("div");
}
public XhtmlNode para() {
return addTag("p");
}
public XhtmlNode pre() {
return addTag("pre");
}
public XhtmlNode pre(String clss) {
return addTag("pre").setAttribute("class", clss);
}
public void br() {
addTag("br");
}
public void hr() {
addTag("hr");
}
public XhtmlNode ul() {
return addTag("ul");
}
public XhtmlNode li() {
return addTag("li");
}
public XhtmlNode b() {
return addTag("b");
}
public XhtmlNode i() {
return addTag("i");
}
public XhtmlNode tx(String cnt) {
return addText(cnt);
}
// differs from tx because it returns the owner node, not the created text
public XhtmlNode txN(String cnt) {
addText(cnt);
return this;
}
public XhtmlNode tx(int cnt) {
return addText(Integer.toString(cnt));
}
public XhtmlNode ah(String href) {
return addTag("a").attribute("href", href);
}
public XhtmlNode ah(String href, String title) {
return addTag("a").attribute("href", href).attribute("title", title);
}
public XhtmlNode img(String src, String alt) {
return addTag("img").attribute("src", src).attribute("alt", alt);
}
public XhtmlNode img(String src, String alt, String title) {
return addTag("img").attribute("src", src).attribute("alt", alt).attribute("title", title);
}
public XhtmlNode an(String href) {
return an(href, " ");
}
public XhtmlNode an(String href, String tx) {
XhtmlNode a = addTag("a").attribute("name", href);
a.tx(tx);
return a;
}
public XhtmlNode span(String style, String title) {
XhtmlNode res = addTag("span");
if (!Utilities.noString(style))
res.attribute("style", style);
if (!Utilities.noString(title))
res.attribute("title", title);
return res;
}
public XhtmlNode code(String text) {
return addTag("code").tx(text);
}
public XhtmlNode code() {
return addTag("code");
}
public XhtmlNode blockquote() {
return addTag("blockquote");
}
@Override
@ -847,36 +692,6 @@ public class XhtmlNode implements IBaseXhtml {
return "p".equals(name);
}
public void markdown(String md, String source) throws IOException {
if (md != null) {
String s = new MarkDownProcessor(Dialect.COMMON_MARK).process(md, source);
XhtmlParser p = new XhtmlParser();
XhtmlNode m;
try {
m = p.parse("<div>"+s+"</div>", "div");
} catch (org.hl7.fhir.exceptions.FHIRFormatError e) {
throw new FHIRFormatError(e.getMessage(), e);
}
getChildNodes().addAll(m.getChildNodes());
}
}
public void innerHTML(String html) throws IOException {
if (html != null) {
XhtmlParser p = new XhtmlParser();
XhtmlNode m;
try {
m = p.parse("<div>"+html+"</div>", "div");
} catch (org.hl7.fhir.exceptions.FHIRFormatError e) {
throw new FHIRFormatError(e.getMessage(), e);
}
getChildNodes().addAll(m.getChildNodes());
}
}
public XhtmlNode sep(String separator) {
// if there's already text, add the separator. otherwise, we'll add it next time
if (!seperated) {
@ -887,8 +702,23 @@ public class XhtmlNode implements IBaseXhtml {
}
// more fluent
public XhtmlNode colspan(String n) {
return setAttribute("colspan", n);
}
// differs from tx because it returns the owner node, not the created text
public XhtmlNode txN(String cnt) {
addText(cnt);
return this;
}
@Override
protected void addChildren(XhtmlNodeList childNodes) {
this.childNodes.addAll(childNodes);
}

View File

@ -0,0 +1,186 @@
package org.hl7.fhir.utilities.xhtml;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class XhtmlNodeList extends XhtmlFluent implements List<XhtmlNode>, java.io.Serializable {
private static final long serialVersionUID = 1L;
private List<XhtmlNode> list = new ArrayList<>();
private boolean inPara;
private boolean inLink;
public boolean isInPara() {
return inPara;
}
public void setInPara(boolean inPara) {
this.inPara = inPara;
}
public boolean isInLink() {
return inLink;
}
public void setInLink(boolean inLink) {
this.inLink = inLink;
}
public XhtmlNode addTag(String name)
{
// if (inPara && name.equals("p")) {
// throw new FHIRException("nested Para");
// }
// if (inLink && name.equals("a")) {
// throw new FHIRException("Nested Link");
// }
XhtmlNode node = new XhtmlNode(NodeType.Element);
node.setName(name);
if (isInPara() || name.equals("p")) {
node.getChildNodes().setInPara(true);
}
if (isInLink() || name.equals("a")) {
node.getChildNodes().setInLink(true);
}
add(node);
return node;
}
public XhtmlNode addText(String content) {
if (content != null) {
XhtmlNode node = new XhtmlNode(NodeType.Text);
node.setContent(content);
add(node);
return node;
} else {
return null;
}
}
@Override
public int size() {
return list.size();
}
@Override
public boolean isEmpty() {
return list.isEmpty();
}
@Override
public boolean contains(Object o) {
return list.contains(o);
}
@Override
public Iterator<XhtmlNode> iterator() {
return list.iterator();
}
@Override
public Object[] toArray() {
return list.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
return list.toArray(a);
}
@Override
public boolean add(XhtmlNode e) {
return list.add(e);
}
@Override
public boolean remove(Object o) {
return list.remove(o);
}
@Override
public boolean containsAll(Collection<?> c) {
return list.containsAll(c);
}
@Override
public boolean addAll(Collection<? extends XhtmlNode> c) {
return list.addAll(c);
}
@Override
public boolean addAll(int index, Collection<? extends XhtmlNode> c) {
return list.addAll(index, c);
}
@Override
public boolean removeAll(Collection<?> c) {
return list.removeAll(c);
}
@Override
public boolean retainAll(Collection<?> c) {
return list.retainAll(c);
}
@Override
public void clear() {
list.clear();
}
@Override
public XhtmlNode get(int index) {
return list.get(index);
}
@Override
public XhtmlNode set(int index, XhtmlNode element) {
return list.set(index, element);
}
@Override
public void add(int index, XhtmlNode element) {
list.add(index, element);
}
@Override
public XhtmlNode remove(int index) {
return list.remove(index);
}
@Override
public int indexOf(Object o) {
return list.indexOf(o);
}
@Override
public int lastIndexOf(Object o) {
return list.lastIndexOf(o);
}
@Override
public ListIterator<XhtmlNode> listIterator() {
return list.listIterator();
}
@Override
public ListIterator<XhtmlNode> listIterator(int index) {
return list.listIterator(index);
}
@Override
public List<XhtmlNode> subList(int fromIndex, int toIndex) {
return list.subList(fromIndex, toIndex);
}
@Override
protected void addChildren(XhtmlNodeList childNodes) {
this.addAll(childNodes);
}
}

View File

@ -16,8 +16,9 @@ import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.exceptions.PathEngineException;
import org.hl7.fhir.r5.conformance.profile.BindingResolution;
import org.hl7.fhir.r5.conformance.profile.ProfileKnowledgeProvider;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities.ProfileKnowledgeProvider;
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
import org.hl7.fhir.r5.formats.XmlParser;
import org.hl7.fhir.r5.model.Base;