more work on PEDefinition
This commit is contained in:
parent
900f471dda
commit
9959183017
|
@ -76,6 +76,7 @@ public class FHIRLexer {
|
|||
private SourceLocation currentStartLocation;
|
||||
private int id;
|
||||
private String name;
|
||||
private boolean liquidMode; // in liquid mode, || terminates the expression and hands the parser back to the host
|
||||
|
||||
public FHIRLexer(String source, String name) throws FHIRLexerException {
|
||||
this.source = source == null ? "" : source;
|
||||
|
@ -201,7 +202,7 @@ public class FHIRLexer {
|
|||
cursor++;
|
||||
if (cursor < source.length() && (source.charAt(cursor) == '/')) {
|
||||
// this is en error - should already have been skipped
|
||||
error("This shoudn't happen?");
|
||||
error("This shouldn't happen?");
|
||||
}
|
||||
current = source.substring(currentStart, cursor);
|
||||
} else if (ch == '$') {
|
||||
|
@ -274,6 +275,12 @@ public class FHIRLexer {
|
|||
throw error("Unterminated string");
|
||||
cursor++;
|
||||
current = "`"+source.substring(currentStart+1, cursor-1)+"`";
|
||||
} else if (ch == '|' && liquidMode) {
|
||||
cursor++;
|
||||
ch = source.charAt(cursor);
|
||||
if (ch == '|')
|
||||
cursor++;
|
||||
current = source.substring(currentStart, cursor);
|
||||
} else if (ch == '@'){
|
||||
int start = cursor;
|
||||
cursor++;
|
||||
|
@ -519,5 +526,14 @@ public class FHIRLexer {
|
|||
public int getCurrentStart() {
|
||||
return currentStart;
|
||||
}
|
||||
public String getSource() {
|
||||
return source;
|
||||
}
|
||||
public boolean isLiquidMode() {
|
||||
return liquidMode;
|
||||
}
|
||||
public void setLiquidMode(boolean liquidMode) {
|
||||
this.liquidMode = liquidMode;
|
||||
}
|
||||
|
||||
}
|
|
@ -243,6 +243,7 @@ public class FHIRPathEngine {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
private IWorkerContext worker;
|
||||
private IEvaluationContext hostServices;
|
||||
|
@ -255,6 +256,7 @@ public class FHIRPathEngine {
|
|||
private String location; // for error messages
|
||||
private boolean allowPolymorphicNames;
|
||||
private boolean doImplicitStringConversion;
|
||||
private boolean liquidMode; // in liquid mode, || terminates the expression and hands the parser back to the host
|
||||
|
||||
// if the fhir path expressions are allowed to use constants beyond those defined in the specification
|
||||
// the application can implement them by providing a constant resolver
|
||||
|
@ -4754,7 +4756,11 @@ public class FHIRPathEngine {
|
|||
}
|
||||
}
|
||||
} else if (hostServices != null) {
|
||||
res = hostServices.resolveReference(context.appInfo, s, refContext);
|
||||
try {
|
||||
res = hostServices.resolveReference(context.appInfo, s, refContext);
|
||||
} catch (Exception e) {
|
||||
res = null;
|
||||
}
|
||||
}
|
||||
if (res != null) {
|
||||
result.add(res);
|
||||
|
@ -6023,5 +6029,13 @@ public class FHIRPathEngine {
|
|||
this.allowPolymorphicNames = allowPolymorphicNames;
|
||||
}
|
||||
|
||||
public boolean isLiquidMode() {
|
||||
return liquidMode;
|
||||
}
|
||||
|
||||
public void setLiquidMode(boolean liquidMode) {
|
||||
this.liquidMode = liquidMode;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.hl7.fhir.r4b.utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
@ -37,6 +38,7 @@ import java.util.Map;
|
|||
*/
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||
import org.hl7.fhir.exceptions.PathEngineException;
|
||||
import org.hl7.fhir.r4b.context.IWorkerContext;
|
||||
import org.hl7.fhir.r4b.model.Base;
|
||||
|
@ -53,6 +55,10 @@ import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
|||
|
||||
public class LiquidEngine implements IEvaluationContext {
|
||||
|
||||
public interface ILiquidRenderingSupport {
|
||||
String renderForLiquid(Object appContext, Base i) throws FHIRException;
|
||||
}
|
||||
|
||||
public interface ILiquidEngineIncludeResolver {
|
||||
public String fetchInclude(LiquidEngine engine, String name);
|
||||
}
|
||||
|
@ -60,6 +66,7 @@ public class LiquidEngine implements IEvaluationContext {
|
|||
private IEvaluationContext externalHostServices;
|
||||
private FHIRPathEngine engine;
|
||||
private ILiquidEngineIncludeResolver includeResolver;
|
||||
private ILiquidRenderingSupport renderingSupport;
|
||||
|
||||
private class LiquidEngineContext {
|
||||
private Object externalContext;
|
||||
|
@ -82,6 +89,7 @@ public class LiquidEngine implements IEvaluationContext {
|
|||
this.externalHostServices = hostServices;
|
||||
engine = new FHIRPathEngine(context);
|
||||
engine.setHostServices(this);
|
||||
engine.setLiquidMode(true);
|
||||
}
|
||||
|
||||
public ILiquidEngineIncludeResolver getIncludeResolver() {
|
||||
|
@ -92,6 +100,14 @@ public class LiquidEngine implements IEvaluationContext {
|
|||
this.includeResolver = includeResolver;
|
||||
}
|
||||
|
||||
public ILiquidRenderingSupport getRenderingSupport() {
|
||||
return renderingSupport;
|
||||
}
|
||||
|
||||
public void setRenderingSupport(ILiquidRenderingSupport renderingSupport) {
|
||||
this.renderingSupport = renderingSupport;
|
||||
}
|
||||
|
||||
public LiquidDocument parse(String source, String sourceName) throws FHIRException {
|
||||
return new LiquidParser(source).parse(sourceName);
|
||||
}
|
||||
|
@ -130,17 +146,84 @@ public class LiquidEngine implements IEvaluationContext {
|
|||
public void evaluate(StringBuilder b, Base resource, LiquidEngineContext ctxt) {
|
||||
b.append(constant);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private enum LiquidFilter {
|
||||
PREPEND;
|
||||
|
||||
public static LiquidFilter fromCode(String code) {
|
||||
if ("prepend".equals(code)) {
|
||||
return PREPEND;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private class LiquidExpressionNode {
|
||||
private LiquidFilter filter; // null at root
|
||||
private ExpressionNode expression; // null for some filters
|
||||
public LiquidExpressionNode(LiquidFilter filter, ExpressionNode expression) {
|
||||
super();
|
||||
this.filter = filter;
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class LiquidStatement extends LiquidNode {
|
||||
private String statement;
|
||||
private ExpressionNode compiled;
|
||||
private List<LiquidExpressionNode> compiled = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void evaluate(StringBuilder b, Base resource, LiquidEngineContext ctxt) throws FHIRException {
|
||||
if (compiled == null)
|
||||
compiled = engine.parse(statement);
|
||||
b.append(engine.evaluateToString(ctxt, resource, resource, resource, compiled));
|
||||
if (compiled.size() == 0) {
|
||||
FHIRLexer lexer = new FHIRLexer(statement, "liquid statement");
|
||||
lexer.setLiquidMode(true);
|
||||
compiled.add(new LiquidExpressionNode(null, engine.parse(lexer)));
|
||||
while (!lexer.done()) {
|
||||
if (lexer.getCurrent().equals("||")) {
|
||||
lexer.next();
|
||||
String f = lexer.getCurrent();
|
||||
LiquidFilter filter = LiquidFilter.fromCode(f);
|
||||
if (filter == null) {
|
||||
lexer.error("Unknown Liquid filter '"+f+"'");
|
||||
}
|
||||
lexer.next();
|
||||
if (!lexer.done() && lexer.getCurrent().equals(":")) {
|
||||
lexer.next();
|
||||
compiled.add(new LiquidExpressionNode(filter, engine.parse(lexer)));
|
||||
} else {
|
||||
compiled.add(new LiquidExpressionNode(filter, null));
|
||||
}
|
||||
} else {
|
||||
lexer.error("Unexpected syntax parsing liquid statement");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String t = null;
|
||||
for (LiquidExpressionNode i : compiled) {
|
||||
if (i.filter == null) { // first
|
||||
t = stmtToString(ctxt, engine.evaluate(ctxt, resource, resource, resource, i.expression));
|
||||
} else switch (i.filter) {
|
||||
case PREPEND:
|
||||
t = stmtToString(ctxt, engine.evaluate(ctxt, resource, resource, resource, i.expression)) + t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
b.append(t);
|
||||
}
|
||||
|
||||
private String stmtToString(LiquidEngineContext ctxt, List<Base> items) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
boolean first = true;
|
||||
for (Base i : items) {
|
||||
if (first) first = false; else b.append(", ");
|
||||
String s = renderingSupport != null ? renderingSupport.renderForLiquid(ctxt.externalContext, i) : null;
|
||||
b.append(s != null ? s : engine.convertToString(i));
|
||||
}
|
||||
return b.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -104,8 +104,8 @@ import org.hl7.fhir.r5.model.Bundle.BundleType;
|
|||
import org.hl7.fhir.r5.model.Bundle.HTTPVerb;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ValueSetComposeComponent;
|
||||
import org.hl7.fhir.r5.profilemodel.ProfiledElement;
|
||||
import org.hl7.fhir.r5.profilemodel.ProfiledElementBuilder;
|
||||
import org.hl7.fhir.r5.profilemodel.PEDefinition;
|
||||
import org.hl7.fhir.r5.profilemodel.PEBuilder;
|
||||
import org.hl7.fhir.r5.renderers.OperationOutcomeRenderer;
|
||||
import org.hl7.fhir.r5.terminologies.CodeSystemUtilities;
|
||||
import org.hl7.fhir.r5.terminologies.TerminologyClient;
|
||||
|
@ -2391,8 +2391,8 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
|||
|
||||
|
||||
@Override
|
||||
public ProfiledElementBuilder getProfiledElementBuilder() {
|
||||
public PEBuilder getProfiledElementBuilder(boolean elementProps) {
|
||||
// TODO Auto-generated method stub
|
||||
return new ProfiledElementBuilder(this);
|
||||
return new PEBuilder(this, elementProps);
|
||||
}
|
||||
}
|
|
@ -65,8 +65,8 @@ import org.hl7.fhir.r5.model.StructureDefinition;
|
|||
import org.hl7.fhir.r5.model.StructureMap;
|
||||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.r5.profilemodel.ProfiledElement;
|
||||
import org.hl7.fhir.r5.profilemodel.ProfiledElementBuilder;
|
||||
import org.hl7.fhir.r5.profilemodel.PEDefinition;
|
||||
import org.hl7.fhir.r5.profilemodel.PEBuilder;
|
||||
import org.hl7.fhir.r5.terminologies.ValueSetExpander.TerminologyServiceErrorClass;
|
||||
import org.hl7.fhir.r5.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
|
||||
import org.hl7.fhir.r5.utils.validation.IResourceValidator;
|
||||
|
@ -803,6 +803,6 @@ public interface IWorkerContext {
|
|||
|
||||
public String getSpecUrl();
|
||||
|
||||
public ProfiledElementBuilder getProfiledElementBuilder();
|
||||
public PEBuilder getProfiledElementBuilder(boolean elementProps);
|
||||
|
||||
}
|
|
@ -61,8 +61,8 @@ import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
|
|||
import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule;
|
||||
import org.hl7.fhir.r5.model.StructureMap.StructureMapModelMode;
|
||||
import org.hl7.fhir.r5.model.StructureMap.StructureMapStructureComponent;
|
||||
import org.hl7.fhir.r5.profilemodel.ProfiledElement;
|
||||
import org.hl7.fhir.r5.profilemodel.ProfiledElementBuilder;
|
||||
import org.hl7.fhir.r5.profilemodel.PEDefinition;
|
||||
import org.hl7.fhir.r5.profilemodel.PEBuilder;
|
||||
import org.hl7.fhir.r5.terminologies.CodeSystemUtilities;
|
||||
import org.hl7.fhir.r5.terminologies.JurisdictionUtilities;
|
||||
import org.hl7.fhir.r5.terminologies.TerminologyClient;
|
||||
|
|
|
@ -0,0 +1,295 @@
|
|||
package org.hl7.fhir.r5.profilemodel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.NotImplementedException;
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities;
|
||||
import org.hl7.fhir.r5.context.IWorkerContext;
|
||||
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.model.Resource;
|
||||
import org.hl7.fhir.r5.model.ResourceFactory;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
|
||||
public class PEBuilder {
|
||||
|
||||
private IWorkerContext context;
|
||||
private ProfileUtilities pu;
|
||||
private boolean elementProps;
|
||||
|
||||
public PEBuilder(IWorkerContext context, boolean elementProps) {
|
||||
super();
|
||||
this.context = context;
|
||||
this.elementProps = elementProps;
|
||||
pu = new ProfileUtilities(context, null, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Given a profile, return a tree of the elements defined in the profile model. This builds the profile model
|
||||
* for the latest version of the nominated profile
|
||||
*
|
||||
* The tree of elements in the profile model is different to those defined in the base resource:
|
||||
* - some elements are removed (max = 0)
|
||||
* - extensions are turned into named elements
|
||||
* - slices are turned into named elements
|
||||
* - element properties - doco, cardinality, binding etc is updated for what the profile says
|
||||
*
|
||||
* Warning: profiles and resources are recursive; you can't iterate this tree until it you get
|
||||
* to the leaves because there are nodes that don't terminate (extensions have extensions)
|
||||
*
|
||||
*/
|
||||
public PEDefinition buildPEDefinition(String url) {
|
||||
StructureDefinition profile = getProfile(url);
|
||||
if (profile == null) {
|
||||
throw new DefinitionException("Unable to find profile for URL '"+url+"'");
|
||||
}
|
||||
StructureDefinition base = context.fetchTypeDefinition(profile.getType());
|
||||
if (base == null) {
|
||||
throw new DefinitionException("Unable to find base type '"+profile.getType()+"' for URL '"+url+"'");
|
||||
}
|
||||
return new PEDefinitionResource(this, base, profile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a profile, return a tree of the elements defined in the profile model. This builds the profile model
|
||||
* for the nominated version of the nominated profile
|
||||
*
|
||||
* The tree of elements in the profile model is different to the the base resource:
|
||||
* - some elements are removed (max = 0)
|
||||
* - extensions are turned into named elements
|
||||
* - slices are turned into named elements
|
||||
* - element properties - doco, cardinality, binding etc is updated for what the profile says
|
||||
*
|
||||
* Warning: profiles and resources can be recursive; you can't iterate this tree until it you get
|
||||
* to the leaves because you will never get to a child that doesn't have children
|
||||
*
|
||||
*/
|
||||
public PEDefinition buildPEDefinition(String url, String version) {
|
||||
StructureDefinition profile = getProfile(url, version);
|
||||
if (profile == null) {
|
||||
throw new DefinitionException("Unable to find profile for URL '"+url+"'");
|
||||
}
|
||||
StructureDefinition base = context.fetchTypeDefinition(profile.getType());
|
||||
if (base == null) {
|
||||
throw new DefinitionException("Unable to find base type '"+profile.getType()+"' for URL '"+url+"'");
|
||||
}
|
||||
return new PEDefinitionResource(this, base, profile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a resource and a profile, return a tree of instance data as defined by the profile model
|
||||
* using the latest version of the profile
|
||||
*
|
||||
* The tree is a facade to the underlying resource - all actual data is stored against the resource,
|
||||
* and retrieved on the fly from the resource, so that applications can work at either level, as
|
||||
* convenient.
|
||||
*
|
||||
* Note that there's a risk that deleting something through the resource while holding
|
||||
* a handle to a PEInstance that is a facade on what is deleted leaves an orphan facade
|
||||
* that will continue to function, but is making changes to resource content that is no
|
||||
* longer part of the resource
|
||||
*
|
||||
*/
|
||||
public PEInstance buildPEInstance(String url, Resource resource) {
|
||||
throw new NotImplementedException("NOt done yet");
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a resource and a profile, return a tree of instance data as defined by the profile model
|
||||
* using the nominated version of the profile
|
||||
*
|
||||
* The tree is a facade to the underlying resource - all actual data is stored against the resource,
|
||||
* and retrieved on the fly from the resource, so that applications can work at either level, as
|
||||
* convenient.
|
||||
*
|
||||
* Note that there's a risk that deleting something through the resource while holding
|
||||
* a handle to a PEInstance that is a facade on what is deleted leaves an orphan facade
|
||||
* that will continue to function, but is making changes to resource content that is no
|
||||
* longer part of the resource
|
||||
*/
|
||||
public PEInstance buildPEInstance(String url, String version, Resource resource) {
|
||||
throw new NotImplementedException("Not done yet");
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a profile, construct an empty resource of the type being profiled (to use as input
|
||||
* to the buildPEInstance method
|
||||
*
|
||||
* No version, because the version doesn't change the type of the resource
|
||||
*/
|
||||
public Resource makeProfileBase(String url) {
|
||||
StructureDefinition profile = getProfile(url);
|
||||
return ResourceFactory.createResource(profile.getType());
|
||||
}
|
||||
|
||||
|
||||
// -- methods below here are only used internally to the package
|
||||
|
||||
private StructureDefinition getProfile(String url) {
|
||||
return context.fetchResource(StructureDefinition.class, url);
|
||||
}
|
||||
|
||||
|
||||
private StructureDefinition getProfile(String url, String version) {
|
||||
return context.fetchResource(StructureDefinition.class, url, version);
|
||||
}
|
||||
|
||||
protected List<PEDefinition> listChildren(StructureDefinition baseStructure, ElementDefinition baseDefinition,
|
||||
StructureDefinition profileStructure, ElementDefinition profiledDefinition, TypeRefComponent t, CanonicalType u) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
protected List<PEDefinition> listChildren(StructureDefinition baseStructure, ElementDefinition baseDefinition, StructureDefinition profileStructure, ElementDefinition profileDefinition, String url) {
|
||||
StructureDefinition profile = profileStructure;
|
||||
List<ElementDefinition> list = pu.getChildList(profile, profileDefinition);
|
||||
if (profileDefinition.getType().size() == 1 || (!profileDefinition.getPath().contains(".")) || list.isEmpty()) {
|
||||
assert url == null || checkType(profileDefinition, url);
|
||||
List<PEDefinition> res = new ArrayList<>();
|
||||
if (list.size() == 0) {
|
||||
profile = context.fetchResource(StructureDefinition.class, url);
|
||||
list = pu.getChildList(profile, profile.getSnapshot().getElementFirstRep());
|
||||
}
|
||||
if (list.size() > 0) {
|
||||
StructureDefinition base = baseStructure;
|
||||
List<ElementDefinition> blist = pu.getChildList(baseStructure, baseDefinition);
|
||||
if (blist.size() == 0) {
|
||||
base = context.fetchTypeDefinition(url);
|
||||
blist = pu.getChildList(base, base.getSnapshot().getElementFirstRep());
|
||||
}
|
||||
int i = 0;
|
||||
while (i < list.size()) {
|
||||
ElementDefinition defn = list.get(i);
|
||||
ElementDefinition bdefn = getByName(blist, defn);
|
||||
if (bdefn == null) {
|
||||
throw new Error("no base definition for "+defn.getId());
|
||||
}
|
||||
if (elementProps || (!Utilities.existsInList(bdefn.getBase().getPath(), "Element.id", "Element.extension"))) {
|
||||
PEDefinitionElement pe = new PEDefinitionElement(this, base, bdefn, profileStructure, defn);
|
||||
pe.setRecursing(profileDefinition == defn || (profile.getDerivation() == TypeDerivationRule.SPECIALIZATION && profile.getType().equals("Extension")));
|
||||
if (defn.hasSlicing()) {
|
||||
if (defn.getSlicing().getRules() != SlicingRules.CLOSED) {
|
||||
res.add(pe);
|
||||
}
|
||||
i++;
|
||||
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(), baseStructure, getByName(blist, defn), profileStructure, list.get(i), defn, ext));
|
||||
} else {
|
||||
res.add(new PEDefinitionSlice(this, list.get(i).getSliceName(), baseStructure, getByName(blist, defn), profileStructure, list.get(i), defn));
|
||||
}
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
res.add(pe);
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
} else if (list.isEmpty()) {
|
||||
throw new DefinitionException("not done yet!");
|
||||
} else {
|
||||
throw new DefinitionException("not done yet");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected List<PEDefinition> listSlices(StructureDefinition baseStructure, ElementDefinition baseDefinition, StructureDefinition profileStructure, ElementDefinition profileDefinition) {
|
||||
List<ElementDefinition> list = pu.getSliceList(profileStructure, profileDefinition);
|
||||
List<PEDefinition> res = new ArrayList<>();
|
||||
for (ElementDefinition ed : list) {
|
||||
if (profileStructure.getDerivation() == TypeDerivationRule.CONSTRAINT && profileStructure.getType().equals("Extension")) {
|
||||
res.add(new PEDefinitionSubExtension(this, baseStructure, baseDefinition, profileStructure, ed));
|
||||
} else {
|
||||
PEDefinitionElement pe = new PEDefinitionElement(this, baseStructure, baseDefinition, profileStructure, ed);
|
||||
pe.setRecursing(profileDefinition == ed || (profileStructure.getDerivation() == TypeDerivationRule.SPECIALIZATION && profileStructure.getType().equals("Extension")));
|
||||
res.add(pe);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
private boolean checkType(ElementDefinition defn, String url) {
|
||||
for (TypeRefComponent t : defn.getType()) {
|
||||
if (("http://hl7.org/fhir/StructureDefinition/"+t.getWorkingCode()).equals(url)) {
|
||||
return true;
|
||||
}
|
||||
for (CanonicalType u : t.getProfile()) {
|
||||
if (url.equals(u.getValue())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private StructureDefinition getExtensionDefinition(ElementDefinition ed) {
|
||||
if ("Extension".equals(ed.getTypeFirstRep().getWorkingCode()) && ed.getTypeFirstRep().getProfile().size() == 1) {
|
||||
return context.fetchResource(StructureDefinition.class, ed.getTypeFirstRep().getProfile().get(0).asStringValue());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private ElementDefinition getByName(List<ElementDefinition> blist, ElementDefinition defn) {
|
||||
for (ElementDefinition ed : blist) {
|
||||
if (ed.getName().equals(defn.getName())) {
|
||||
return ed;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public PEType makeType(TypeRefComponent t) {
|
||||
if (t.hasProfile()) {
|
||||
StructureDefinition sd = context.fetchResource(StructureDefinition.class, t.getProfile().get(0).getValue());
|
||||
if (sd == null) {
|
||||
return new PEType(tail(t.getProfile().get(0).getValue()), t.getWorkingCode(), t.getProfile().get(0).getValue());
|
||||
} else {
|
||||
return new PEType(sd.getName(), t.getWorkingCode(), t.getProfile().get(0).getValue());
|
||||
}
|
||||
} else {
|
||||
return makeType(t.getWorkingCode());
|
||||
}
|
||||
}
|
||||
|
||||
public PEType makeType(TypeRefComponent t, CanonicalType u) {
|
||||
StructureDefinition sd = context.fetchResource(StructureDefinition.class, u.getValue());
|
||||
if (sd == null) {
|
||||
return new PEType(tail(u.getValue()), t.getWorkingCode(), u.getValue());
|
||||
} else {
|
||||
return new PEType(sd.getName(), t.getWorkingCode(), u.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public PEType makeType(String tn) {
|
||||
return new PEType(tn, tn, "http://hl7.org/fhir/StructureDefinition/"+ tn);
|
||||
}
|
||||
|
||||
private String tail(String value) {
|
||||
return value.contains("/") ? value.substring(value.lastIndexOf("/")+1) : value;
|
||||
}
|
||||
|
||||
|
||||
public List<ElementDefinition> getChildren(StructureDefinition profileStructure, ElementDefinition profiledDefinition) {
|
||||
return pu.getChildList(profileStructure, profiledDefinition);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
package org.hl7.fhir.r5.profilemodel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.NotImplementedException;
|
||||
import org.hl7.fhir.r5.model.Base;
|
||||
import org.hl7.fhir.r5.model.ElementDefinition;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
|
||||
public abstract class PEDefinition {
|
||||
|
||||
protected PEBuilder builder;
|
||||
protected String name;
|
||||
protected StructureDefinition baseStructure;
|
||||
protected ElementDefinition baseDefinition;
|
||||
protected StructureDefinition profileStructure;
|
||||
protected ElementDefinition profiledDefinition;
|
||||
protected List<PEType> types;
|
||||
protected Map<String, List<PEDefinition>> children = new HashMap<>();
|
||||
private boolean recursing;
|
||||
|
||||
/**
|
||||
* Don't create one of these directly - always use the public methods on ProfiledElementBuilder
|
||||
*
|
||||
* @param builder
|
||||
* @param baseElement
|
||||
* @param profiledElement
|
||||
* @param data
|
||||
*/
|
||||
protected PEDefinition(PEBuilder builder, String name, ElementDefinition baseDefinition,
|
||||
ElementDefinition profiledDefinition, Base data) {
|
||||
super();
|
||||
this.builder = builder;
|
||||
this.name = name;
|
||||
this.baseDefinition = baseDefinition;
|
||||
this.profiledDefinition = profiledDefinition;
|
||||
// this.data = data;
|
||||
}
|
||||
|
||||
protected PEDefinition(PEBuilder builder, String name, StructureDefinition base, ElementDefinition baseDefinition,
|
||||
StructureDefinition profile, ElementDefinition profiledDefinition) {
|
||||
this.builder = builder;
|
||||
this.name = name;
|
||||
this.baseStructure = base;
|
||||
this.baseDefinition = baseDefinition;
|
||||
this.profileStructure = profile;
|
||||
this.profiledDefinition = profiledDefinition;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return The name of the element or slice in the profile (always unique amongst children)
|
||||
*/
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The name of the element in the resource (may be different to the slice name)
|
||||
*/
|
||||
public String schemaName() {
|
||||
return baseDefinition.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a list of types. There is usually at least one type; it might be Element, Type, BackboneElement or BackboneType
|
||||
*
|
||||
* The following elements don't have types (true primitives): Element.id. Extension.url, PrimitiveType.value
|
||||
*/
|
||||
public List<PEType> types() {
|
||||
if (types == null) {
|
||||
List<PEType> ltypes = new ArrayList<>();
|
||||
listTypes(ltypes);
|
||||
types = ltypes;
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
protected abstract void listTypes(List<PEType> types);
|
||||
|
||||
/**
|
||||
* @return The minimum number of repeats allowed
|
||||
*/
|
||||
public int min() {
|
||||
return profiledDefinition.getMin();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the maximum number of repeats allowed
|
||||
*/
|
||||
public int max() {
|
||||
return "*".equals(profiledDefinition.getMax()) ? Integer.MAX_VALUE : Integer.parseInt(profiledDefinition.getMax());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the definition of the element in the profile (fully populated)
|
||||
*
|
||||
* Note that the profile definition might be the same as a base definition, when the tree runs off the end of what's profiled
|
||||
*/
|
||||
public ElementDefinition definition() {
|
||||
return profiledDefinition;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the definition of the element in the base specification
|
||||
*
|
||||
* Note that the profile definition might be the same as a base definition, when the tree runs off the end of what's profiled
|
||||
*/
|
||||
public ElementDefinition baseDefinition() {
|
||||
return baseDefinition;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the short documentation of the definition (shown in the profile table view)
|
||||
*/
|
||||
public String shortDocumentation() {
|
||||
return profiledDefinition.getShort();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the full definition of the element (markdown syntax)
|
||||
*/
|
||||
public String documentation() {
|
||||
return profiledDefinition.getDefinition();
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @return if the profiled definition has a value set
|
||||
// */
|
||||
// public ValueSet expansion() {
|
||||
// throw new NotImplementedException("Not done yet");
|
||||
// }
|
||||
//
|
||||
/**
|
||||
* @param typeUrl - the url of one of the types listed in types()
|
||||
* @return - the list of children for the nominated type
|
||||
*
|
||||
* Warning: profiles and resources can be recursive; you can't iterate this tree until you get
|
||||
* to the leaves because you will never get to a child that doesn't have children (extensions have extensions etc)
|
||||
*
|
||||
*/
|
||||
public List<PEDefinition> children(String typeUrl) {
|
||||
if (children.containsKey(typeUrl)) {
|
||||
return children.get(typeUrl);
|
||||
}
|
||||
List<PEDefinition> res = new ArrayList<>();
|
||||
makeChildren(typeUrl, res);
|
||||
children.put(typeUrl, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
protected abstract void makeChildren(String typeUrl, List<PEDefinition> children);
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name+"("+schemaName()+"):"+types().toString()+" ["+min()+":"+(max() == Integer.MAX_VALUE ? "*" : max() )+"] \""+shortDocumentation()+"\"";
|
||||
}
|
||||
|
||||
public boolean isRecursing() {
|
||||
return recursing;
|
||||
}
|
||||
|
||||
public void setRecursing(boolean recursing) {
|
||||
this.recursing = recursing;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package org.hl7.fhir.r5.profilemodel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.r5.model.CanonicalType;
|
||||
import org.hl7.fhir.r5.model.ElementDefinition;
|
||||
import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
|
||||
public class PEDefinitionElement extends PEDefinition {
|
||||
|
||||
public PEDefinitionElement(PEBuilder builder,
|
||||
StructureDefinition baseStructure, ElementDefinition baseDefinition,
|
||||
StructureDefinition profileStructure, ElementDefinition profileDefinition) {
|
||||
super(builder, baseDefinition.getName(), baseStructure, baseDefinition, profileStructure, profileDefinition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void listTypes(List<PEType> types) {
|
||||
for (TypeRefComponent t : profiledDefinition.getType()) {
|
||||
if (t.hasProfile()) {
|
||||
for (CanonicalType u : t.getProfile()) {
|
||||
types.add(builder.makeType(t, u));
|
||||
}
|
||||
} else if (!t.getCode().startsWith("http://hl7.org/fhirpath/")) {
|
||||
types.add(new PEType(t.getWorkingCode(), t.getWorkingCode(), "http://hl7.org/fhir/StructureDefinition/"+t.getWorkingCode()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void makeChildren(String typeUrl, List<PEDefinition> children) {
|
||||
children.addAll(builder.listChildren(baseStructure, baseDefinition, profileStructure, profiledDefinition, typeUrl));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,50 +1,54 @@
|
|||
package org.hl7.fhir.r5.profilemodel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
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.ElementDefinition.TypeRefComponent;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
|
||||
public class PEExtension extends ProfiledElement {
|
||||
public class PEDefinitionExtension extends PEDefinition {
|
||||
|
||||
private StructureDefinition extension;
|
||||
private ElementDefinition sliceDefinition;
|
||||
|
||||
public PEExtension(ProfiledElementBuilder builder, String name,
|
||||
public PEDefinitionExtension(PEBuilder builder, String name,
|
||||
StructureDefinition baseStructure, ElementDefinition baseDefinition,
|
||||
StructureDefinition profileStructure, ElementDefinition profileDefinition,
|
||||
ElementDefinition sliceDefinition, StructureDefinition extension) {
|
||||
super(builder, name, baseStructure, baseDefinition, profileStructure, profileDefinition, sliceDefinition);
|
||||
super(builder, name, baseStructure, baseDefinition, profileStructure, profileDefinition);
|
||||
this.sliceDefinition = sliceDefinition;
|
||||
this.extension= extension;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> types() {
|
||||
List<String> res = new ArrayList<>();
|
||||
public void listTypes(List<PEType> types) {
|
||||
ElementDefinition eed = extension.getSnapshot().getElementByPath("Extension.extension");
|
||||
ElementDefinition ved = extension.getSnapshot().getElementByPath("Extension.value[x]");
|
||||
if (ved.isRequired() || eed.isProhibited()) {
|
||||
for (TypeRefComponent t : ved.getType()) {
|
||||
if (t.hasProfile()) {
|
||||
for (CanonicalType u : t.getProfile()) {
|
||||
res.add(t.getWorkingCode()+"["+u.getValue()+"]");
|
||||
types.add(builder.makeType(t, u));
|
||||
}
|
||||
} else {
|
||||
res.add(t.getWorkingCode());
|
||||
types.add(builder.makeType(t.getWorkingCode()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
res.add("Extension");
|
||||
types.add(builder.makeType("Extension"));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProfiledElement> children(String type) {
|
||||
throw new Error("Not done yet");
|
||||
|
||||
protected void makeChildren(String typeUrl, List<PEDefinition> children) {
|
||||
ElementDefinition eed = extension.getSnapshot().getElementByPath("Extension.extension");
|
||||
ElementDefinition ved = extension.getSnapshot().getElementByPath("Extension.value[x]");
|
||||
if (ved.isRequired() || eed.isProhibited()) {
|
||||
children.addAll(builder.listChildren(extension, ved, extension, ved, typeUrl));
|
||||
} else {
|
||||
children.addAll(builder.listSlices(extension, eed, extension, eed));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package org.hl7.fhir.r5.profilemodel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
|
||||
public class PEDefinitionResource extends PEDefinition {
|
||||
|
||||
public PEDefinitionResource(PEBuilder builder, StructureDefinition base, StructureDefinition profile) {
|
||||
super(builder, profile.getName(), base, base.getSnapshot().getElementFirstRep(), profile, profile.getSnapshot().getElementFirstRep());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void listTypes(List<PEType> types) {
|
||||
types.add(new PEType(profileStructure.getName(), profileStructure.getType(), profileStructure.getUrl()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void makeChildren(String typeUrl, List<PEDefinition> children) {
|
||||
children.addAll(builder.listChildren(baseStructure, baseDefinition, profileStructure, profiledDefinition, null));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package org.hl7.fhir.r5.profilemodel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.r5.model.Base;
|
||||
import org.hl7.fhir.r5.model.ElementDefinition;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
|
||||
public class PEDefinitionSlice extends PEDefinition {
|
||||
|
||||
protected ElementDefinition sliceDefinition;
|
||||
|
||||
public PEDefinitionSlice(PEBuilder builder, String name, StructureDefinition baseStructure,
|
||||
ElementDefinition baseDefinition, StructureDefinition profileStructure, ElementDefinition profileDefinition,
|
||||
ElementDefinition sliceDefinition) {
|
||||
super(builder, name, baseStructure, baseDefinition, profileStructure, profileDefinition);
|
||||
this.sliceDefinition = sliceDefinition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void listTypes(List<PEType> types) {
|
||||
throw new Error("Not done yet");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void makeChildren(String typeUrl, List<PEDefinition> children) {
|
||||
throw new Error("Not done yet");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package org.hl7.fhir.r5.profilemodel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.r5.model.CanonicalType;
|
||||
import org.hl7.fhir.r5.model.ElementDefinition;
|
||||
import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
|
||||
public class PEDefinitionSubExtension extends PEDefinition {
|
||||
|
||||
public PEDefinitionSubExtension(PEBuilder builder, StructureDefinition baseStructure, ElementDefinition baseDefinition, StructureDefinition profileStructure, ElementDefinition profileDefinition) {
|
||||
super(builder, profileDefinition.getSliceName(), baseStructure, baseDefinition, profileStructure, profileDefinition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void listTypes(List<PEType> types) {
|
||||
List<ElementDefinition> childDefs = builder.getChildren(profileStructure, profiledDefinition);
|
||||
ElementDefinition eed = getElementByName(childDefs, "extension");
|
||||
ElementDefinition ved = getElementByName(childDefs, "value[x]");
|
||||
if (ved.isRequired() || eed.isProhibited()) {
|
||||
for (TypeRefComponent t : ved.getType()) {
|
||||
if (t.hasProfile()) {
|
||||
for (CanonicalType u : t.getProfile()) {
|
||||
types.add(builder.makeType(t, u));
|
||||
}
|
||||
} else {
|
||||
types.add(builder.makeType(t.getWorkingCode()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
types.add(builder.makeType("Extension"));
|
||||
}
|
||||
}
|
||||
|
||||
private ElementDefinition getElementByName(List<ElementDefinition> children, String name) {
|
||||
for (ElementDefinition ed : children) {
|
||||
if (name.equals(ed.getName())) {
|
||||
return ed;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void makeChildren(String typeUrl, List<PEDefinition> children) {
|
||||
List<ElementDefinition> childDefs = builder.getChildren(profileStructure, profiledDefinition);
|
||||
ElementDefinition eed = getElementByName(childDefs, "extension");
|
||||
ElementDefinition ved = getElementByName(childDefs, "value[x]");
|
||||
if (ved.isRequired() || eed.isProhibited()) {
|
||||
children.addAll(builder.listChildren(baseStructure, baseDefinition, profileStructure, ved, typeUrl));
|
||||
} else {
|
||||
children.addAll(builder.listSlices(baseStructure, baseDefinition, profileStructure, eed));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
package org.hl7.fhir.r5.profilemodel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.r5.model.CanonicalType;
|
||||
import org.hl7.fhir.r5.model.ElementDefinition;
|
||||
import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
|
||||
public class PEElement extends ProfiledElement {
|
||||
|
||||
public PEElement(ProfiledElementBuilder builder,
|
||||
StructureDefinition baseStructure, ElementDefinition baseDefinition,
|
||||
StructureDefinition profileStructure, ElementDefinition profileDefinition) {
|
||||
super(builder, baseDefinition.getName(), baseStructure, baseDefinition, profileStructure, profileDefinition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> types() {
|
||||
List<String> res = new ArrayList<>();
|
||||
for (TypeRefComponent t : profiledDefinition.getType()) {
|
||||
if (t.hasProfile()) {
|
||||
for (CanonicalType u : t.getProfile()) {
|
||||
res.add(t.getWorkingCode()+"["+u.getValue()+"]");
|
||||
}
|
||||
} else if (!t.getCode().startsWith("http://hl7.org/fhirpath/")) {
|
||||
res.add(t.getWorkingCode());
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProfiledElement> children(String type) {
|
||||
if (children == null) {
|
||||
for (TypeRefComponent t : profiledDefinition.getType()) {
|
||||
if (t.hasProfile()) {
|
||||
for (CanonicalType u : t.getProfile()) {
|
||||
if ((t.getWorkingCode()+"["+u.getValue()+"]").equals(type)) {
|
||||
children = builder.listChildren(baseStructure, baseDefinition, profileStructure, profiledDefinition, t, u);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (t.getWorkingCode().equals(type)) {
|
||||
children = builder.listChildren(baseStructure, baseDefinition, profileStructure, profiledDefinition, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (children != null) {
|
||||
return children;
|
||||
}
|
||||
throw new DefinitionException("Unable to understand type '"+type+"'");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package org.hl7.fhir.r5.profilemodel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.r5.model.Base;
|
||||
import org.hl7.fhir.r5.model.DataType;
|
||||
import org.hl7.fhir.r5.model.Resource;
|
||||
|
||||
public abstract class PEInstance {
|
||||
|
||||
private PEDefinition definition;
|
||||
private Base data;
|
||||
|
||||
protected PEInstance(PEDefinition definition, Base data) {
|
||||
super();
|
||||
this.definition = definition;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return definition information about this instance data
|
||||
*/
|
||||
public abstract PEDefinition definition();
|
||||
|
||||
/**
|
||||
* @return the type of this element
|
||||
*/
|
||||
public abstract PEType type();
|
||||
|
||||
/**
|
||||
* @return all the children of this instance data
|
||||
*/
|
||||
public abstract List<PEInstance> children();
|
||||
|
||||
/**
|
||||
* @return all the children of this instance data for the named property
|
||||
*/
|
||||
public abstract List<PEInstance> children(String name);
|
||||
|
||||
/**
|
||||
* @return all the children of this instance data with the named property and the named type (for polymorphic
|
||||
*/
|
||||
public abstract List<PEInstance> children(String name, String type);
|
||||
|
||||
/**
|
||||
* @return make a child, and append it to existing children (if they exist)
|
||||
*/
|
||||
public abstract PEInstance makeChild(String name);
|
||||
|
||||
/**
|
||||
* remove the nominated child from the resource
|
||||
*/
|
||||
public abstract void removeChild(PEInstance child);
|
||||
|
||||
|
||||
public enum PEInstanceDataKind {
|
||||
Resource, Complex, DataType, PrimitiveValue
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the kind of data behind this profiled node
|
||||
*/
|
||||
public abstract PEInstanceDataKind getDataKind();
|
||||
|
||||
/**
|
||||
* @return if dataKind = Resource, get the underlying resource, otherwise an exception
|
||||
*/
|
||||
public abstract Resource asResource();
|
||||
|
||||
/**
|
||||
* @return if dataKind = Datatype, get the underlying resource, otherwise an exception
|
||||
*/
|
||||
public abstract DataType asDataType();
|
||||
|
||||
/**
|
||||
* @return if dataKind = PrimitiveValue, get the underlying resource, otherwise an exception
|
||||
*
|
||||
* Note that this is for e.g. String.value, not String itself
|
||||
*/
|
||||
public abstract String getPrimitiveValue();
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
package org.hl7.fhir.r5.profilemodel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
|
||||
public class PEResource extends ProfiledElement {
|
||||
|
||||
public PEResource(ProfiledElementBuilder builder, StructureDefinition base, StructureDefinition profile) {
|
||||
super(builder, profile.getName(), base, base.getSnapshot().getElementFirstRep(), profile, profile.getSnapshot().getElementFirstRep());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> types() {
|
||||
List<String> res = new ArrayList<>();
|
||||
res.add(profileStructure.getType());
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProfiledElement> children(String type) {
|
||||
if (children == null) {
|
||||
children = builder.listChildren(baseStructure, baseDefinition, profileStructure, profiledDefinition, null);
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
package org.hl7.fhir.r5.profilemodel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.r5.model.ElementDefinition;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
|
||||
public class PESlice extends ProfiledElement {
|
||||
|
||||
public PESlice(ProfiledElementBuilder builder, String name,
|
||||
StructureDefinition baseStructure, ElementDefinition baseDefinition,
|
||||
StructureDefinition profileStructure, ElementDefinition profileDefinition,
|
||||
ElementDefinition sliceDefinition) {
|
||||
super(builder, name, baseStructure, baseDefinition, profileStructure, profileDefinition, sliceDefinition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> types() {
|
||||
throw new Error("Not done yet");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProfiledElement> children(String type) {
|
||||
throw new Error("Not done yet");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package org.hl7.fhir.r5.profilemodel;
|
||||
|
||||
public class PEType {
|
||||
private String name;
|
||||
private String type;
|
||||
private String url;
|
||||
public PEType(String name, String type, String url) {
|
||||
super();
|
||||
this.name = name;
|
||||
this.url = url;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Human presentable name
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* The concrete FHIR type name for the type
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* URL that identifies the type
|
||||
* @return
|
||||
*/
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return (name.equals(type) ? name : name+"->"+type)+"["+url+"]";
|
||||
}
|
||||
|
||||
}
|
|
@ -1,216 +0,0 @@
|
|||
package org.hl7.fhir.r5.profilemodel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.NotImplementedException;
|
||||
import org.hl7.fhir.r5.model.Base;
|
||||
import org.hl7.fhir.r5.model.ElementDefinition;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
|
||||
public abstract class ProfiledElement {
|
||||
|
||||
protected ProfiledElementBuilder builder;
|
||||
protected String name;
|
||||
protected StructureDefinition baseStructure;
|
||||
protected ElementDefinition baseDefinition;
|
||||
protected StructureDefinition profileStructure;
|
||||
protected ElementDefinition profiledDefinition;
|
||||
protected Base data; // might be null if we're not attached to an instance
|
||||
protected List<ProfiledElement> children;
|
||||
protected Object sliceDefinition;
|
||||
|
||||
/**
|
||||
* Don't create one of these directly - always use the public methods on ProfiledElementBuilder
|
||||
*
|
||||
* @param builder
|
||||
* @param baseElement
|
||||
* @param profiledElement
|
||||
* @param data
|
||||
*/
|
||||
protected ProfiledElement(ProfiledElementBuilder builder, String name, ElementDefinition baseDefinition,
|
||||
ElementDefinition profiledDefinition, Base data) {
|
||||
super();
|
||||
this.builder = builder;
|
||||
this.name = name;
|
||||
this.baseDefinition = baseDefinition;
|
||||
this.profiledDefinition = profiledDefinition;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
protected ProfiledElement(ProfiledElementBuilder builder, String name, StructureDefinition base, ElementDefinition baseDefinition,
|
||||
StructureDefinition profile, ElementDefinition profiledDefinition) {
|
||||
this.builder = builder;
|
||||
this.name = name;
|
||||
this.baseStructure = base;
|
||||
this.baseDefinition = baseDefinition;
|
||||
this.profileStructure = profile;
|
||||
this.profiledDefinition = profiledDefinition;
|
||||
}
|
||||
|
||||
public ProfiledElement(ProfiledElementBuilder builder, String name, StructureDefinition base, ElementDefinition baseDefinition,
|
||||
StructureDefinition profile, ElementDefinition profiledDefinition, ElementDefinition sliceDefinition) {
|
||||
this.builder = builder;
|
||||
this.name = name;
|
||||
this.baseStructure = base;
|
||||
this.baseDefinition = baseDefinition;
|
||||
this.profileStructure = profile;
|
||||
this.profiledDefinition = profiledDefinition;
|
||||
this.sliceDefinition = sliceDefinition;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The name of the element or slice in the profile (always unique amongst children)
|
||||
*/
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The name of the element in the resource (may be different to the slice name)
|
||||
*/
|
||||
public String schemaName() {
|
||||
return baseDefinition.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a list of types. There is usually at least one type; it might be Element, Type, BackboneElement or BackboneType
|
||||
*
|
||||
* The following elements don't have types (true primitives): Element.id. Extension.url, PrimitiveType.value
|
||||
*/
|
||||
public abstract List<String> types();
|
||||
|
||||
/**
|
||||
* @return The minimum number of repeats allowed
|
||||
*/
|
||||
public int min() {
|
||||
return profiledDefinition.getMin();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the maximum number of repeats allowed
|
||||
*/
|
||||
public int max() {
|
||||
return "*".equals(profiledDefinition.getMax()) ? Integer.MAX_VALUE : Integer.parseInt(profiledDefinition.getMax());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the definition of the element in the profile (fully populated)
|
||||
*/
|
||||
public ElementDefinition definition() {
|
||||
return profiledDefinition;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the definition of the element in the base specification
|
||||
*/
|
||||
public ElementDefinition baseDefinition() {
|
||||
return baseDefinition;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the short documentation of the definition (shown in the profile table view)
|
||||
*/
|
||||
public String shortDocumentation() {
|
||||
return profiledDefinition.getShort();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the full definition of the element (markdown syntax)
|
||||
*/
|
||||
public String documentation() {
|
||||
return profiledDefinition.getDefinition();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return if the base definition
|
||||
*/
|
||||
public ValueSet expansion() {
|
||||
throw new NotImplementedException("Not done yet");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type - one of the types listed in types()
|
||||
* @return - the list of children for the nominated type
|
||||
*
|
||||
* Note that the children returned from this instance can run off the
|
||||
* end of the data provided, and then inDataMode() is false
|
||||
*
|
||||
* Warning: profiles and resources can be recursive; you can't iterate this tree until it you get
|
||||
* to the leaves because you will never get to a child that doesn't have children
|
||||
*
|
||||
*/
|
||||
public abstract List<ProfiledElement> children(String type);
|
||||
//
|
||||
// // -- instance data ---------------------------------------
|
||||
//
|
||||
// /**
|
||||
// * true if the profiled element is part of a tree built based on
|
||||
// * a resource
|
||||
// */
|
||||
// public void inDataMode() {
|
||||
// throw new NotImplementedException("Not done yet");
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * return a list of profiled elements that are instances of
|
||||
// * of this element - these are attached to acual underlying data in the resource
|
||||
// * @return
|
||||
// */
|
||||
// public List<ProfiledElement> instances() {
|
||||
// throw new NotImplementedException("Not done yet");
|
||||
// };
|
||||
//
|
||||
// /**
|
||||
// * Create a new instance of data that conforms to this profiled element
|
||||
// *
|
||||
// * @return
|
||||
// */
|
||||
// public ProfiledElement addInstance(){
|
||||
// throw new NotImplementedException("Not done yet");
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * @return true if this element can have a primitive value
|
||||
// *
|
||||
// * Note that an element can have extensions as well as a value, so that doesn't mean it can't have children
|
||||
// */
|
||||
// public boolean canHavePrimitiveValue() {
|
||||
// throw new NotImplementedException("Not done yet");
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * @return true if this element has a primitive value
|
||||
// *
|
||||
// * Note that an element can have extensions as well as a value, so that doesn't mean it can't have children
|
||||
// */
|
||||
// public boolean hasPrimitiveValue() {
|
||||
// throw new NotImplementedException("Not done yet");
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * @return true if this element has a primitive value
|
||||
// *
|
||||
// * Note that an element can have extensions as well as a value, so that doesn't mean it can't have children
|
||||
// */
|
||||
// public String getPrimitiveValue() {
|
||||
// throw new NotImplementedException("Not done yet");
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * @return true if this element has a primitive value
|
||||
// *
|
||||
// * Note that an element can have extensions as well as a value, so that doesn't mean it can't have children
|
||||
// */
|
||||
// public String setPrimitiveValue() {
|
||||
// throw new NotImplementedException("Not done yet");
|
||||
// }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name+"("+schemaName()+"):"+types().toString()+" ["+min()+":"+(max() == Integer.MAX_VALUE ? "*" : max() )+"] \""+shortDocumentation()+"\"";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,221 +0,0 @@
|
|||
package org.hl7.fhir.r5.profilemodel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.NotImplementedException;
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities;
|
||||
import org.hl7.fhir.r5.context.IWorkerContext;
|
||||
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.model.Resource;
|
||||
import org.hl7.fhir.r5.model.ResourceFactory;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
|
||||
public class ProfiledElementBuilder {
|
||||
|
||||
private IWorkerContext context;
|
||||
private ProfileUtilities pu;
|
||||
|
||||
public ProfiledElementBuilder(IWorkerContext context) {
|
||||
super();
|
||||
this.context = context;
|
||||
pu = new ProfileUtilities(context, null, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Given a profile, return a tree of elements in the profile model. This builds the profile model
|
||||
* for the latest version of the nominated profile
|
||||
*
|
||||
* THe tree of elements in the profile model is different to the the base resource:
|
||||
* - some elements are removed (max = 0)
|
||||
* - extensions are turned into named elements
|
||||
* - slices are turned into named elements
|
||||
* - element properties - doco, cardinality, binding etc is updated for what the profile says
|
||||
*
|
||||
* When built with this method, the profile element can't have instance data
|
||||
*
|
||||
* Warning: profiles and resources are recursive; you can't iterate this tree until it you get
|
||||
* to the leaves because there are nodes that don't terminate (extensions have extensions)
|
||||
*
|
||||
*/
|
||||
public ProfiledElement buildProfileElement(String url) {
|
||||
StructureDefinition profile = getProfile(url);
|
||||
if (profile == null) {
|
||||
throw new DefinitionException("Unable to find profile for URL '"+url+"'");
|
||||
}
|
||||
StructureDefinition base = context.fetchTypeDefinition(profile.getType());
|
||||
if (base == null) {
|
||||
throw new DefinitionException("Unable to find base type '"+profile.getType()+"' for URL '"+url+"'");
|
||||
}
|
||||
return new PEResource(this, base, profile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a profile, return a tree of elements in the profile model. This builds the profile model
|
||||
* for the nominated version of the nominated profile
|
||||
*
|
||||
* THe tree of elements in the profile model is different to the the base resource:
|
||||
* - some elements are removed (max = 0)
|
||||
* - extensions are turned into named elements
|
||||
* - slices are turned into named elements
|
||||
* - element properties - doco, cardinality, binding etc is updated for what the profile says
|
||||
*
|
||||
* When built with this method, the profile element can't have instance data
|
||||
*
|
||||
* Warning: profiles and resources can be recursive; you can't iterate this tree until it you get
|
||||
* to the leaves because you will never get to a child that doesn't have children
|
||||
*
|
||||
*/
|
||||
public ProfiledElement buildProfileElement(String url, String version) {
|
||||
StructureDefinition profile = getProfile(url, version);
|
||||
if (profile == null) {
|
||||
throw new DefinitionException("Unable to find profile for URL '"+url+"'");
|
||||
}
|
||||
StructureDefinition base = context.fetchTypeDefinition(profile.getType());
|
||||
if (base == null) {
|
||||
throw new DefinitionException("Unable to find base type '"+profile.getType()+"' for URL '"+url+"'");
|
||||
}
|
||||
return new PEResource(this, base, profile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a profile, return a tree of elements in the profile model with matching instance data.
|
||||
* This builds the profile model for the latest version of the nominated profile and matches
|
||||
* the data in the resource against the profile. Data can be added or read from the profile element
|
||||
*
|
||||
* THe tree of elements in the profile model is different to the the base resource:
|
||||
* - some elements are removed (max = 0)
|
||||
* - extensions are turned into named elements
|
||||
* - slices are turned into named elements
|
||||
* - element properties - doco, cardinality, binding etc is updated for what the profile says
|
||||
*
|
||||
* When built with this method, the profile element can't have instance data
|
||||
*
|
||||
* Warning: profiles and resources can be recursive; you can't iterate this tree until it you get
|
||||
* to the leaves because you will never get to a child that doesn't have children
|
||||
*
|
||||
*/
|
||||
public ProfiledElement buildProfileElement(String url, Resource resource) {
|
||||
throw new NotImplementedException("NOt done yet");
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a profile, return a tree of elements in the profile model with matching instance data.
|
||||
* This builds the profile model for the nominated version of the nominated profile and matches
|
||||
* the data in the resource against the profile. Data can be added or read from the profile element
|
||||
*
|
||||
* THe tree of elements in the profile model is different to the the base resource:
|
||||
* - some elements are removed (max = 0)
|
||||
* - extensions are turned into named elements
|
||||
* - slices are turned into named elements
|
||||
* - element properties - doco, cardinality, binding etc is updated for what the profile says
|
||||
*
|
||||
* When built with this method, the profile element can't have instance data
|
||||
*
|
||||
*/
|
||||
public ProfiledElement buildProfileElement(String url, String version, Resource resource) {
|
||||
throw new NotImplementedException("NOt done yet");
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a profile, construct an empty resource of the type being profiled (to use as input
|
||||
* to the buildProfileElement method
|
||||
*
|
||||
* No version, because the version doesn't change the type of the resource
|
||||
*/
|
||||
public Resource makeProfileBase(String url) {
|
||||
StructureDefinition profile = getProfile(url);
|
||||
return ResourceFactory.createResource(profile.getType());
|
||||
}
|
||||
|
||||
|
||||
// -- methods below here are only used internally to the package
|
||||
|
||||
private StructureDefinition getProfile(String url) {
|
||||
return context.fetchResource(StructureDefinition.class, url);
|
||||
}
|
||||
|
||||
|
||||
private StructureDefinition getProfile(String url, String version) {
|
||||
return context.fetchResource(StructureDefinition.class, url, version);
|
||||
}
|
||||
|
||||
protected List<ProfiledElement> listChildren(StructureDefinition baseStructure, ElementDefinition baseDefinition,
|
||||
StructureDefinition profileStructure, ElementDefinition profiledDefinition, TypeRefComponent t, CanonicalType u) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
protected List<ProfiledElement> listChildren(StructureDefinition baseStructure, ElementDefinition baseDefinition, StructureDefinition profileStructure, ElementDefinition profileDefinition, TypeRefComponent t) {
|
||||
if (profileDefinition.getType().size() == 1 || (!profileDefinition.getPath().contains("."))) {
|
||||
assert profileDefinition.getType().size() != 1 || profileDefinition.getType().contains(t);
|
||||
List<ProfiledElement> res = new ArrayList<>();
|
||||
StructureDefinition profile = profileStructure;
|
||||
List<ElementDefinition> list = pu.getChildList(profile, profileDefinition);
|
||||
if (list.size() == 0) {
|
||||
profile = t.hasProfile() ? context.fetchResource(StructureDefinition.class, t.getProfile().get(0).getValue()) : context.fetchTypeDefinition(t.getWorkingCode());
|
||||
list = pu.getChildList(profile, profile.getSnapshot().getElementFirstRep());
|
||||
}
|
||||
if (list.size() > 0) {
|
||||
StructureDefinition base = baseStructure;
|
||||
List<ElementDefinition> blist = pu.getChildList(baseStructure, baseDefinition);
|
||||
if (blist.size() == 0) {
|
||||
base = context.fetchTypeDefinition(t.getWorkingCode());
|
||||
blist = pu.getChildList(base, base.getSnapshot().getElementFirstRep());
|
||||
}
|
||||
int i = 0;
|
||||
while (i < list.size()) {
|
||||
ElementDefinition defn = list.get(i);
|
||||
if (defn.hasSlicing()) {
|
||||
if (defn.getSlicing().getRules() != SlicingRules.CLOSED) {
|
||||
res.add(new PEElement(this, base, getByName(blist, defn), profileStructure, defn));
|
||||
}
|
||||
i++;
|
||||
while (i < list.size() && list.get(i).getPath().equals(defn.getPath())) {
|
||||
StructureDefinition ext = getExtensionDefinition(list.get(i));
|
||||
if (ext != null) {
|
||||
res.add(new PEExtension(this, list.get(i).getSliceName(), baseStructure, getByName(blist, defn), profileStructure, list.get(i), defn, ext));
|
||||
} else {
|
||||
res.add(new PESlice(this, list.get(i).getSliceName(), baseStructure, getByName(blist, defn), profileStructure, list.get(i), defn));
|
||||
}
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
res.add(new PEElement(this, base, getByName(blist, defn), profileStructure, defn));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
} else {
|
||||
throw new DefinitionException("not done yet");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private StructureDefinition getExtensionDefinition(ElementDefinition ed) {
|
||||
if ("Extension".equals(ed.getTypeFirstRep().getWorkingCode()) && ed.getTypeFirstRep().getProfile().size() == 1) {
|
||||
return context.fetchResource(StructureDefinition.class, ed.getTypeFirstRep().getProfile().get(0).asStringValue());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private ElementDefinition getByName(List<ElementDefinition> blist, ElementDefinition defn) {
|
||||
for (ElementDefinition ed : blist) {
|
||||
if (ed.getName().equals(defn.getName())) {
|
||||
return ed;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -4,8 +4,9 @@ import java.io.IOException;
|
|||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.r5.context.IWorkerContext;
|
||||
import org.hl7.fhir.r5.profilemodel.ProfiledElement;
|
||||
import org.hl7.fhir.r5.profilemodel.ProfiledElementBuilder;
|
||||
import org.hl7.fhir.r5.profilemodel.PEDefinition;
|
||||
import org.hl7.fhir.r5.profilemodel.PEType;
|
||||
import org.hl7.fhir.r5.profilemodel.PEBuilder;
|
||||
import org.hl7.fhir.r5.test.utils.TestPackageLoader;
|
||||
import org.hl7.fhir.r5.test.utils.TestingUtilities;
|
||||
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
|
||||
|
@ -16,26 +17,37 @@ import org.junit.jupiter.api.Test;
|
|||
public class ProfiledElementTests {
|
||||
|
||||
|
||||
private IWorkerContext ctxt;
|
||||
|
||||
|
||||
public void load() throws IOException {
|
||||
if (ctxt == null) {
|
||||
ctxt = TestingUtilities.getSharedWorkerContext();
|
||||
FilesystemPackageCacheManager pc = new FilesystemPackageCacheManager(true);
|
||||
NpmPackage npm = pc.loadPackage("hl7.fhir.us.core", "5.0.0");
|
||||
ctxt.loadFromPackage(npm, new TestPackageLoader(new String[] { "StructureDefinition" }));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testPatientCore() throws IOException {
|
||||
IWorkerContext ctxt = TestingUtilities.getSharedWorkerContext();
|
||||
FilesystemPackageCacheManager pc = new FilesystemPackageCacheManager(true);
|
||||
NpmPackage npm = pc.loadPackage("hl7.fhir.us.core", "5.0.0");
|
||||
ctxt.loadFromPackage(npm, new TestPackageLoader(new String[] { "StructureDefinition" }));
|
||||
public void testUSPatientCore() throws IOException {
|
||||
load();
|
||||
|
||||
ProfiledElement pe = new ProfiledElementBuilder(ctxt).buildProfileElement("http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient");
|
||||
PEDefinition pe = new PEBuilder(ctxt, true).buildPEDefinition("http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient");
|
||||
|
||||
Assertions.assertEquals("USCorePatientProfile", pe.name());
|
||||
Assertions.assertEquals("Patient", pe.schemaName());
|
||||
Assertions.assertEquals(0, pe.min());
|
||||
Assertions.assertEquals(Integer.MAX_VALUE, pe.max());
|
||||
Assertions.assertEquals("Patient", pe.types().get(0));
|
||||
Assertions.assertEquals("Patient", pe.types().get(0).getType());
|
||||
Assertions.assertEquals("USCorePatientProfile", pe.types().get(0).getName());
|
||||
Assertions.assertNotNull(pe.definition());
|
||||
Assertions.assertNotNull(pe.baseDefinition());
|
||||
Assertions.assertEquals("Information about an individual or animal receiving health care services", pe.shortDocumentation());
|
||||
Assertions.assertEquals("\\-", pe.documentation());
|
||||
|
||||
List<ProfiledElement> children = pe.children("Patient");
|
||||
List<PEDefinition> children = pe.children("Patient");
|
||||
Assertions.assertEquals(28, children.size());
|
||||
|
||||
pe = children.get(9);
|
||||
|
@ -43,7 +55,7 @@ public class ProfiledElementTests {
|
|||
Assertions.assertEquals("extension", pe.schemaName());
|
||||
Assertions.assertEquals(0, pe.min());
|
||||
Assertions.assertEquals(1, pe.max());
|
||||
Assertions.assertEquals("code", pe.types().get(0));
|
||||
Assertions.assertEquals("code", pe.types().get(0).getName());
|
||||
Assertions.assertNotNull(pe.definition());
|
||||
Assertions.assertNotNull(pe.baseDefinition());
|
||||
Assertions.assertEquals("Extension", pe.shortDocumentation());
|
||||
|
@ -55,7 +67,7 @@ public class ProfiledElementTests {
|
|||
Assertions.assertEquals("extension", pe.schemaName());
|
||||
Assertions.assertEquals(0, pe.min());
|
||||
Assertions.assertEquals(1, pe.max());
|
||||
Assertions.assertEquals("Extension", pe.types().get(0));
|
||||
Assertions.assertEquals("Extension", pe.types().get(0).getName());
|
||||
Assertions.assertNotNull(pe.definition());
|
||||
Assertions.assertNotNull(pe.baseDefinition());
|
||||
Assertions.assertEquals("US Core ethnicity Extension", pe.shortDocumentation());
|
||||
|
@ -67,14 +79,14 @@ public class ProfiledElementTests {
|
|||
Assertions.assertEquals("identifier", pe.schemaName());
|
||||
Assertions.assertEquals(1, pe.min());
|
||||
Assertions.assertEquals(Integer.MAX_VALUE, pe.max());
|
||||
Assertions.assertEquals("Identifier", pe.types().get(0));
|
||||
Assertions.assertEquals("Identifier", pe.types().get(0).getName());
|
||||
Assertions.assertNotNull(pe.definition());
|
||||
Assertions.assertNotNull(pe.baseDefinition());
|
||||
Assertions.assertEquals("An identifier for this patient", pe.shortDocumentation());
|
||||
Assertions.assertEquals("An identifier for this patient.", pe.documentation());
|
||||
|
||||
|
||||
List<ProfiledElement> iChildren = pe.children("Identifier");
|
||||
List<PEDefinition> iChildren = pe.children("http://hl7.org/fhir/StructureDefinition/Identifier");
|
||||
Assertions.assertEquals(8, iChildren.size());
|
||||
|
||||
|
||||
|
@ -84,13 +96,13 @@ public class ProfiledElementTests {
|
|||
Assertions.assertEquals("use", pe.schemaName());
|
||||
Assertions.assertEquals(0, pe.min());
|
||||
Assertions.assertEquals(1, pe.max());
|
||||
Assertions.assertEquals("code", pe.types().get(0));
|
||||
Assertions.assertEquals("code", pe.types().get(0).getName());
|
||||
Assertions.assertNotNull(pe.definition());
|
||||
Assertions.assertNotNull(pe.baseDefinition());
|
||||
Assertions.assertEquals("usual | official | temp | secondary | old (If known)", pe.shortDocumentation());
|
||||
Assertions.assertEquals("The purpose of this identifier.", pe.documentation());
|
||||
|
||||
iChildren = pe.children("code");
|
||||
iChildren = pe.children("http://hl7.org/fhir/StructureDefinition/code");
|
||||
Assertions.assertEquals(3, iChildren.size());
|
||||
|
||||
pe = iChildren.get(2);
|
||||
|
@ -121,38 +133,66 @@ public class ProfiledElementTests {
|
|||
Assertions.assertEquals("extension", pe.schemaName());
|
||||
Assertions.assertEquals(0, pe.min());
|
||||
Assertions.assertEquals(Integer.MAX_VALUE, pe.max());
|
||||
Assertions.assertEquals("Extension", pe.types().get(0));
|
||||
Assertions.assertEquals("Extension", pe.types().get(0).getName());
|
||||
Assertions.assertNotNull(pe.definition());
|
||||
Assertions.assertNotNull(pe.baseDefinition());
|
||||
Assertions.assertEquals("Additional content defined by implementations", pe.shortDocumentation());
|
||||
Assertions.assertEquals("May be used to represent additional information that is not part of the basic definition of the resource. To make the use of extensions safe and manageable, there is a strict set of governance applied to the definition and use of extensions. Though any implementer can define an extension, there is a set of requirements that SHALL be met as part of the definition of the extension.", pe.documentation());
|
||||
|
||||
iChildren = pe.children("Extension");
|
||||
iChildren = pe.children("http://hl7.org/fhir/StructureDefinition/Extension");
|
||||
Assertions.assertEquals(4, iChildren.size());
|
||||
pe = iChildren.get(1);
|
||||
Assertions.assertEquals("extension", pe.name());
|
||||
Assertions.assertEquals("extension", pe.schemaName());
|
||||
Assertions.assertEquals(0, pe.min());
|
||||
Assertions.assertEquals(Integer.MAX_VALUE, pe.max());
|
||||
Assertions.assertEquals("Extension", pe.types().get(0));
|
||||
Assertions.assertEquals("Extension", pe.types().get(0).getName());
|
||||
Assertions.assertNotNull(pe.definition());
|
||||
Assertions.assertNotNull(pe.baseDefinition());
|
||||
Assertions.assertEquals("Additional content defined by implementations", pe.shortDocumentation());
|
||||
Assertions.assertEquals("May be used to represent additional information that is not part of the basic definition of the element. To make the use of extensions safe and manageable, there is a strict set of governance applied to the definition and use of extensions. Though any implementer can define an extension, there is a set of requirements that SHALL be met as part of the definition of the extension.", pe.documentation());
|
||||
|
||||
|
||||
iChildren = pe.children("Extension");
|
||||
iChildren = pe.children("http://hl7.org/fhir/StructureDefinition/Extension");
|
||||
Assertions.assertEquals(4, iChildren.size());
|
||||
pe = iChildren.get(1);
|
||||
Assertions.assertEquals("extension", pe.name());
|
||||
Assertions.assertEquals("extension", pe.schemaName());
|
||||
Assertions.assertEquals(0, pe.min());
|
||||
Assertions.assertEquals(Integer.MAX_VALUE, pe.max());
|
||||
Assertions.assertEquals("Extension", pe.types().get(0));
|
||||
Assertions.assertEquals("Extension", pe.types().get(0).getName());
|
||||
Assertions.assertNotNull(pe.definition());
|
||||
Assertions.assertNotNull(pe.baseDefinition());
|
||||
Assertions.assertEquals("Additional content defined by implementations", pe.shortDocumentation());
|
||||
Assertions.assertEquals("May be used to represent additional information that is not part of the basic definition of the element. To make the use of extensions safe and manageable, there is a strict set of governance applied to the definition and use of extensions. Though any implementer can define an extension, there is a set of requirements that SHALL be met as part of the definition of the extension.", pe.documentation());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dumpUSPatientCore() throws IOException {
|
||||
load();
|
||||
|
||||
PEDefinition pe = new PEBuilder(ctxt, false).buildPEDefinition("http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient");
|
||||
dump(pe, "");
|
||||
}
|
||||
|
||||
|
||||
private void dump(PEDefinition pe, String indent) {
|
||||
System.out.println(indent+pe.toString());
|
||||
if (!pe.isRecursing() && indent.length() < 20) {
|
||||
if (pe.types().size() == 1) {
|
||||
for (PEDefinition p : pe.children(pe.types().get(0).getUrl())) {
|
||||
dump(p, indent+" ");
|
||||
}
|
||||
} else {
|
||||
for (PEType t : pe.types()) {
|
||||
System.out.println(indent+" +type:"+t.getName());
|
||||
for (PEDefinition p : pe.children(t.getUrl())) {
|
||||
dump(p, indent+" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue