Search in sources :

Example 81 with CanonicalType

use of org.hl7.fhir.r5.model.CanonicalType in project org.hl7.fhir.core by hapifhir.

the class CapabilityStatementRenderer method render.

public boolean render(XhtmlNode x, CapabilityStatement conf) throws FHIRFormatError, DefinitionException, IOException {
    x.h2().addText(conf.getName());
    addMarkdown(x, conf.getDescription());
    if (conf.getRest().size() > 0) {
        CapabilityStatementRestComponent rest = conf.getRest().get(0);
        XhtmlNode t = x.table(null);
        addTableRow(t, "Mode", rest.getMode().toString());
        addMarkdown(addTableRow(t, "Description"), rest.getDocumentation());
        addTableRow(t, "Transaction", showOp(rest, SystemRestfulInteraction.TRANSACTION));
        addTableRow(t, "System History", showOp(rest, SystemRestfulInteraction.HISTORYSYSTEM));
        addTableRow(t, "System Search", showOp(rest, SystemRestfulInteraction.SEARCHSYSTEM));
        boolean hasVRead = false;
        boolean hasPatch = false;
        boolean hasDelete = false;
        boolean hasHistory = false;
        boolean hasUpdates = false;
        for (CapabilityStatementRestResourceComponent r : rest.getResource()) {
            hasVRead = hasVRead || hasOp(r, TypeRestfulInteraction.VREAD);
            hasPatch = hasPatch || hasOp(r, TypeRestfulInteraction.PATCH);
            hasDelete = hasDelete || hasOp(r, TypeRestfulInteraction.DELETE);
            hasHistory = hasHistory || hasOp(r, TypeRestfulInteraction.HISTORYTYPE);
            hasUpdates = hasUpdates || hasOp(r, TypeRestfulInteraction.HISTORYINSTANCE);
        }
        t = x.table(null);
        XhtmlNode tr = t.tr();
        tr.th().b().tx("Resource Type");
        tr.th().b().tx("Profile");
        tr.th().b().attribute("title", "GET a resource (read interaction)").tx("Read");
        if (hasVRead)
            tr.th().b().attribute("title", "GET past versions of resources (vread interaction)").tx("V-Read");
        tr.th().b().attribute("title", "GET all set of resources of the type (search interaction)").tx("Search");
        tr.th().b().attribute("title", "PUT a new resource version (update interaction)").tx("Update");
        if (hasPatch)
            tr.th().b().attribute("title", "PATCH a new resource version (patch interaction)").tx("Patch");
        tr.th().b().attribute("title", "POST a new resource (create interaction)").tx("Create");
        if (hasDelete)
            tr.th().b().attribute("title", "DELETE a resource (delete interaction)").tx("Delete");
        if (hasUpdates)
            tr.th().b().attribute("title", "GET changes to a resource (history interaction on instance)").tx("Updates");
        if (hasHistory)
            tr.th().b().attribute("title", "GET changes for all resources of the type (history interaction on type)").tx("History");
        XhtmlNode profCell = null;
        boolean hasProf = false;
        boolean hasSupProf = false;
        for (CapabilityStatementRestResourceComponent r : rest.getResource()) {
            tr = t.tr();
            tr.td().addText(r.getType());
            // Show profiles
            profCell = tr.td();
            hasProf = r.hasProfile();
            hasSupProf = r.hasSupportedProfile();
            if ((!hasProf) && (!hasSupProf)) {
                profCell.nbsp();
            } else if (hasProf) {
                profCell.ah(r.getProfile()).addText(r.getProfile());
                if (hasSupProf) {
                    profCell.br();
                    profCell.addText("Additional supported profiles:");
                    for (CanonicalType sp : r.getSupportedProfile()) {
                        profCell.br();
                        profCell.nbsp().nbsp();
                        profCell.ah(sp.getValue()).addText(sp.getValue());
                    }
                }
            } else {
                // Case of only supported profiles
                profCell.addText("Supported profiles:");
                for (CanonicalType sp : r.getSupportedProfile()) {
                    profCell.br();
                    profCell.nbsp().nbsp();
                    profCell.ah(sp.getValue()).addText(sp.getValue());
                }
            }
            // Show capabilities
            tr.td().addText(showOp(r, TypeRestfulInteraction.READ));
            if (hasVRead)
                tr.td().addText(showOp(r, TypeRestfulInteraction.VREAD));
            tr.td().addText(showOp(r, TypeRestfulInteraction.SEARCHTYPE));
            tr.td().addText(showOp(r, TypeRestfulInteraction.UPDATE));
            if (hasPatch)
                tr.td().addText(showOp(r, TypeRestfulInteraction.PATCH));
            tr.td().addText(showOp(r, TypeRestfulInteraction.CREATE));
            if (hasDelete)
                tr.td().addText(showOp(r, TypeRestfulInteraction.DELETE));
            if (hasUpdates)
                tr.td().addText(showOp(r, TypeRestfulInteraction.HISTORYINSTANCE));
            if (hasHistory)
                tr.td().addText(showOp(r, TypeRestfulInteraction.HISTORYTYPE));
        }
    }
    return true;
}
Also used : CapabilityStatementRestComponent(org.hl7.fhir.r4b.model.CapabilityStatement.CapabilityStatementRestComponent) CapabilityStatementRestResourceComponent(org.hl7.fhir.r4b.model.CapabilityStatement.CapabilityStatementRestResourceComponent) CanonicalType(org.hl7.fhir.r4b.model.CanonicalType) XhtmlNode(org.hl7.fhir.utilities.xhtml.XhtmlNode)

Example 82 with CanonicalType

use of org.hl7.fhir.r5.model.CanonicalType in project org.hl7.fhir.core by hapifhir.

the class InstanceValidator method checkReference.

private void checkReference(ValidatorHostContext hostContext, List<ValidationMessage> errors, String path, Element element, StructureDefinition profile, ElementDefinition container, String parentType, NodeStack stack) throws FHIRException {
    Reference reference = ObjectConverter.readAsReference(element);
    String ref = reference.getReference();
    if (Utilities.noString(ref)) {
        if (!path.contains("element.pattern")) {
            // this business rule doesn't apply to patterns
            if (Utilities.noString(reference.getIdentifier().getSystem()) && Utilities.noString(reference.getIdentifier().getValue())) {
                warning(errors, IssueType.STRUCTURE, element.line(), element.col(), path, !Utilities.noString(element.getNamedChildValue("display")), I18nConstants.REFERENCE_REF_NODISPLAY);
            }
        }
        return;
    } else if (Utilities.existsInList(ref, "http://tools.ietf.org/html/bcp47")) {
        // special known URLs that can't be validated but are known to be valid
        return;
    }
    warning(errors, IssueType.STRUCTURE, element.line(), element.col(), path, !isSuspiciousReference(ref), I18nConstants.REFERENCE_REF_SUSPICIOUS, ref);
    ResolvedReference we = localResolve(ref, stack, errors, path, hostContext.getRootResource(), hostContext.getGroupingResource(), element);
    String refType;
    if (ref.startsWith("#")) {
        refType = "contained";
    } else {
        if (we == null) {
            refType = "remote";
        } else {
            refType = "bundled";
        }
    }
    ReferenceValidationPolicy pol;
    if (refType.equals("contained") || refType.equals("bundled")) {
        pol = ReferenceValidationPolicy.CHECK_VALID;
    } else {
        if (policyAdvisor == null)
            pol = ReferenceValidationPolicy.IGNORE;
        else
            pol = policyAdvisor.policyForReference(this, hostContext.getAppContext(), path, ref);
    }
    if (pol.checkExists()) {
        if (we == null) {
            if (!refType.equals("contained")) {
                if (fetcher == null) {
                    throw new FHIRException(context.formatMessage(I18nConstants.RESOURCE_RESOLUTION_SERVICES_NOT_PROVIDED));
                } else {
                    Element ext = null;
                    if (fetchCache.containsKey(ref)) {
                        ext = fetchCache.get(ref);
                    } else {
                        try {
                            ext = fetcher.fetch(this, hostContext.getAppContext(), ref);
                        } catch (IOException e) {
                            if (STACK_TRACE)
                                e.printStackTrace();
                            throw new FHIRException(e);
                        }
                        if (ext != null) {
                            setParents(ext);
                            fetchCache.put(ref, ext);
                        }
                    }
                    we = ext == null ? null : makeExternalRef(ext, path);
                }
            }
        }
        boolean ok = (allowExamples && (ref.contains("example.org") || ref.contains("acme.com"))) || (we != null || pol == ReferenceValidationPolicy.CHECK_TYPE_IF_EXISTS);
        rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, ok, I18nConstants.REFERENCE_REF_CANTRESOLVE, ref);
    }
    String ft;
    if (we != null) {
        ft = we.getType();
    } else {
        ft = tryParse(ref);
    }
    if (reference.hasType()) {
        // R4 onwards...
        // the type has to match the specified
        String tu = isAbsolute(reference.getType()) ? reference.getType() : "http://hl7.org/fhir/StructureDefinition/" + reference.getType();
        TypeRefComponent containerType = container.getType("Reference");
        if (!containerType.hasTargetProfile(tu) && !containerType.hasTargetProfile("http://hl7.org/fhir/StructureDefinition/Resource") && !containerType.getTargetProfile().isEmpty()) {
            boolean matchingResource = false;
            for (CanonicalType target : containerType.getTargetProfile()) {
                StructureDefinition sd = resolveProfile(profile, target.asStringValue());
                if (rule(errors, IssueType.NOTFOUND, element.line(), element.col(), path, sd != null, I18nConstants.REFERENCE_REF_CANTRESOLVEPROFILE, target.asStringValue())) {
                    if (("http://hl7.org/fhir/StructureDefinition/" + sd.getType()).equals(tu)) {
                        matchingResource = true;
                        break;
                    }
                }
            }
            rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, matchingResource, I18nConstants.REFERENCE_REF_WRONGTARGET, reference.getType(), container.getType("Reference").getTargetProfile());
        }
        // the type has to match the actual
        rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, ft == null || ft.equals(reference.getType()), I18nConstants.REFERENCE_REF_BADTARGETTYPE, reference.getType(), ft);
    }
    if (we != null && pol.checkType()) {
        if (warning(errors, IssueType.STRUCTURE, element.line(), element.col(), path, ft != null, I18nConstants.REFERENCE_REF_NOTYPE)) {
            // we validate as much as we can. First, can we infer a type from the profile?
            boolean ok = false;
            TypeRefComponent type = getReferenceTypeRef(container.getType());
            if (type.hasTargetProfile() && !type.hasTargetProfile("http://hl7.org/fhir/StructureDefinition/Resource")) {
                Set<String> types = new HashSet<>();
                List<StructureDefinition> profiles = new ArrayList<>();
                for (UriType u : type.getTargetProfile()) {
                    StructureDefinition sd = resolveProfile(profile, u.getValue());
                    if (rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, sd != null, I18nConstants.REFERENCE_REF_CANTRESOLVEPROFILE, u.getValue())) {
                        types.add(sd.getType());
                        if (ft.equals(sd.getType())) {
                            ok = true;
                            profiles.add(sd);
                        }
                    }
                }
                if (!pol.checkValid()) {
                    rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, profiles.size() > 0, I18nConstants.REFERENCE_REF_CANTMATCHTYPE, ref, StringUtils.join("; ", type.getTargetProfile()));
                } else {
                    Map<StructureDefinition, List<ValidationMessage>> badProfiles = new HashMap<>();
                    Map<StructureDefinition, List<ValidationMessage>> goodProfiles = new HashMap<>();
                    int goodCount = 0;
                    for (StructureDefinition pr : profiles) {
                        List<ValidationMessage> profileErrors = new ArrayList<ValidationMessage>();
                        validateResource(we.hostContext(hostContext, pr), profileErrors, we.getResource(), we.getFocus(), pr, IdStatus.OPTIONAL, we.getStack().resetIds());
                        if (!hasErrors(profileErrors)) {
                            goodCount++;
                            goodProfiles.put(pr, profileErrors);
                            trackUsage(pr, hostContext, element);
                        } else {
                            badProfiles.put(pr, profileErrors);
                        }
                    }
                    if (goodCount == 1) {
                        if (showMessagesFromReferences) {
                            for (ValidationMessage vm : goodProfiles.values().iterator().next()) {
                                if (!errors.contains(vm)) {
                                    errors.add(vm);
                                }
                            }
                        }
                    } else if (goodProfiles.size() == 0) {
                        if (!isShowMessagesFromReferences()) {
                            rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, areAllBaseProfiles(profiles), I18nConstants.REFERENCE_REF_CANTMATCHCHOICE, ref, asList(type.getTargetProfile()));
                            for (StructureDefinition sd : badProfiles.keySet()) {
                                slicingHint(errors, IssueType.STRUCTURE, element.line(), element.col(), path, false, false, context.formatMessage(I18nConstants.DETAILS_FOR__MATCHING_AGAINST_PROFILE_, ref, sd.getUrl()), errorSummaryForSlicingAsHtml(badProfiles.get(sd)), errorSummaryForSlicingAsText(badProfiles.get(sd)));
                            }
                        } else {
                            rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, profiles.size() == 1, I18nConstants.REFERENCE_REF_CANTMATCHCHOICE, ref, asList(type.getTargetProfile()));
                            for (List<ValidationMessage> messages : badProfiles.values()) {
                                for (ValidationMessage vm : messages) {
                                    if (!errors.contains(vm)) {
                                        errors.add(vm);
                                    }
                                }
                            }
                        }
                    } else {
                        if (!isShowMessagesFromReferences()) {
                            warning(errors, IssueType.STRUCTURE, element.line(), element.col(), path, false, I18nConstants.REFERENCE_REF_MULTIPLEMATCHES, ref, asListByUrl(goodProfiles.keySet()));
                            for (StructureDefinition sd : badProfiles.keySet()) {
                                slicingHint(errors, IssueType.STRUCTURE, element.line(), element.col(), path, false, false, context.formatMessage(I18nConstants.DETAILS_FOR__MATCHING_AGAINST_PROFILE_, ref, sd.getUrl()), errorSummaryForSlicingAsHtml(badProfiles.get(sd)), errorSummaryForSlicingAsText(badProfiles.get(sd)));
                            }
                        } else {
                            warning(errors, IssueType.STRUCTURE, element.line(), element.col(), path, false, I18nConstants.REFERENCE_REF_MULTIPLEMATCHES, ref, asListByUrl(goodProfiles.keySet()));
                            for (List<ValidationMessage> messages : goodProfiles.values()) {
                                for (ValidationMessage vm : messages) {
                                    if (!errors.contains(vm)) {
                                        errors.add(vm);
                                    }
                                }
                            }
                        }
                    }
                }
                rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, ok, I18nConstants.REFERENCE_REF_BADTARGETTYPE, ft, types.toString());
            }
            if (type.hasAggregation() && !noCheckAggregation) {
                boolean modeOk = false;
                CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
                for (Enumeration<AggregationMode> mode : type.getAggregation()) {
                    b.append(mode.getCode());
                    if (mode.getValue().equals(AggregationMode.CONTAINED) && refType.equals("contained"))
                        modeOk = true;
                    else if (mode.getValue().equals(AggregationMode.BUNDLED) && refType.equals("bundled"))
                        modeOk = true;
                    else if (mode.getValue().equals(AggregationMode.REFERENCED) && (refType.equals("bundled") || refType.equals("remote")))
                        modeOk = true;
                }
                rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, modeOk, I18nConstants.REFERENCE_REF_AGGREGATION, refType, b.toString());
            }
        }
    }
    if (we == null) {
        TypeRefComponent type = getReferenceTypeRef(container.getType());
        boolean okToRef = !type.hasAggregation() || type.hasAggregation(AggregationMode.REFERENCED);
        rule(errors, IssueType.REQUIRED, -1, -1, path, okToRef, I18nConstants.REFERENCE_REF_NOTFOUND_BUNDLE, ref);
    }
    if (we == null && ft != null && assumeValidRestReferences) {
        // if we == null, we inferred ft from the reference. if we are told to treat this as gospel
        TypeRefComponent type = getReferenceTypeRef(container.getType());
        Set<String> types = new HashSet<>();
        StructureDefinition sdFT = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + ft);
        boolean ok = false;
        for (CanonicalType tp : type.getTargetProfile()) {
            StructureDefinition sd = context.fetchResource(StructureDefinition.class, tp.getValue());
            if (sd != null) {
                types.add(sd.getType());
            }
            StructureDefinition sdF = sdFT;
            while (sdF != null) {
                if (sdF.getType().equals(sd.getType())) {
                    ok = true;
                    break;
                }
                sdF = sdF.hasBaseDefinition() ? context.fetchResource(StructureDefinition.class, sdF.getBaseDefinition()) : null;
            }
        }
        rule(errors, IssueType.STRUCTURE, element.line(), element.col(), path, types.isEmpty() || ok, I18nConstants.REFERENCE_REF_BADTARGETTYPE2, ft, ref, types);
    }
    if (pol == ReferenceValidationPolicy.CHECK_VALID) {
    // todo....
    }
}
Also used : ResolvedReference(org.hl7.fhir.validation.instance.utils.ResolvedReference) ValidationMessage(org.hl7.fhir.utilities.validation.ValidationMessage) HashMap(java.util.HashMap) NamedElement(org.hl7.fhir.r5.elementmodel.ParserBase.NamedElement) IndexedElement(org.hl7.fhir.validation.instance.utils.IndexedElement) SpecialElement(org.hl7.fhir.r5.elementmodel.Element.SpecialElement) Element(org.hl7.fhir.r5.elementmodel.Element) ArrayList(java.util.ArrayList) AggregationMode(org.hl7.fhir.r5.model.ElementDefinition.AggregationMode) CanonicalType(org.hl7.fhir.r5.model.CanonicalType) UriType(org.hl7.fhir.r5.model.UriType) StructureDefinition(org.hl7.fhir.r5.model.StructureDefinition) TypeRefComponent(org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent) ArrayList(java.util.ArrayList) List(java.util.List) HashSet(java.util.HashSet) Reference(org.hl7.fhir.r5.model.Reference) ResolvedReference(org.hl7.fhir.validation.instance.utils.ResolvedReference) CommaSeparatedStringBuilder(org.hl7.fhir.utilities.CommaSeparatedStringBuilder) IOException(java.io.IOException) FHIRException(org.hl7.fhir.exceptions.FHIRException) ContactPoint(org.hl7.fhir.r5.model.ContactPoint)

Example 83 with CanonicalType

use of org.hl7.fhir.r5.model.CanonicalType in project org.hl7.fhir.core by hapifhir.

the class ProfileUtilities method allProfilesMustSupport.

public static boolean allProfilesMustSupport(List<CanonicalType> profiles) {
    boolean all = true;
    boolean any = false;
    for (CanonicalType u : profiles) {
        all = all && isMustSupport(u);
        any = any || isMustSupport(u);
    }
    return !all && !any;
}
Also used : CanonicalType(org.hl7.fhir.r4b.model.CanonicalType)

Example 84 with CanonicalType

use of org.hl7.fhir.r5.model.CanonicalType in project org.hl7.fhir.core by hapifhir.

the class ProfileUtilities method processPaths.

/**
 * @param trimDifferential
 * @param srcSD
 * @throws DefinitionException, FHIRException
 * @throws Exception
 */
private ElementDefinition processPaths(String indent, StructureDefinitionSnapshotComponent result, StructureDefinitionSnapshotComponent base, StructureDefinitionDifferentialComponent differential, int baseCursor, int diffCursor, int baseLimit, int diffLimit, String url, String webUrl, String profileName, String contextPathSrc, String contextPathDst, boolean trimDifferential, String contextName, String resultPathBase, boolean slicingDone, ElementDefinition slicer, String typeSlicingPath, List<ElementRedirection> redirector, StructureDefinition srcSD) throws DefinitionException, FHIRException {
    if (debug) {
        System.out.println(indent + "PP @ " + resultPathBase + " / " + contextPathSrc + " : base = " + baseCursor + " to " + baseLimit + ", diff = " + diffCursor + " to " + diffLimit + " (slicing = " + slicingDone + ", k " + (redirector == null ? "null" : redirector.toString()) + ")");
    }
    ElementDefinition res = null;
    List<TypeSlice> typeList = new ArrayList<>();
    // just repeat processing entries until we run out of our allowed scope (1st entry, the allowed scope is all the entries)
    while (baseCursor <= baseLimit) {
        // get the current focus of the base, and decide what to do
        ElementDefinition currentBase = base.getElement().get(baseCursor);
        String cpath = fixedPathSource(contextPathSrc, currentBase.getPath(), redirector);
        if (debug) {
            System.out.println(indent + " - " + cpath + ": base = " + baseCursor + " (" + descED(base.getElement(), baseCursor) + ") to " + baseLimit + " (" + descED(base.getElement(), baseLimit) + "), diff = " + diffCursor + " (" + descED(differential.getElement(), diffCursor) + ") to " + diffLimit + " (" + descED(differential.getElement(), diffLimit) + ") " + "(slicingDone = " + slicingDone + ") (diffpath= " + (differential.getElement().size() > diffCursor ? differential.getElement().get(diffCursor).getPath() : "n/a") + ")");
        }
        // get a list of matching elements in scope
        List<ElementDefinition> diffMatches = getDiffMatches(differential, cpath, diffCursor, diffLimit, profileName);
        // in the simple case, source is not sliced.
        if (!currentBase.hasSlicing() || cpath.equals(typeSlicingPath)) {
            if (diffMatches.isEmpty()) {
                // the differential doesn't say anything about this item
                // so we just copy it in
                ElementDefinition outcome = updateURLs(url, webUrl, currentBase.copy());
                outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc));
                updateFromBase(outcome, currentBase);
                updateConstraintSources(outcome, srcSD.getUrl());
                markDerived(outcome);
                if (resultPathBase == null)
                    resultPathBase = outcome.getPath();
                else if (!outcome.getPath().startsWith(resultPathBase))
                    throw new DefinitionException(context.formatMessage(I18nConstants.ADDING_WRONG_PATH__OUTCOMEGETPATH___RESULTPATHBASE__, outcome.getPath(), resultPathBase));
                result.getElement().add(outcome);
                if (hasInnerDiffMatches(differential, cpath, diffCursor, diffLimit, base.getElement(), true)) {
                    // did we implicitly step into a new type?
                    if (baseHasChildren(base, currentBase)) {
                        // not a new type here
                        processPaths(indent + "  ", result, base, differential, baseCursor + 1, diffCursor, baseLimit, diffLimit, url, webUrl, profileName, contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD);
                        baseCursor = indexOfFirstNonChild(base, currentBase, baseCursor + 1, baseLimit);
                    } else {
                        if (outcome.getType().size() == 0 && !outcome.hasContentReference()) {
                            throw new DefinitionException(context.formatMessage(I18nConstants._HAS_NO_CHILDREN__AND_NO_TYPES_IN_PROFILE_, cpath, differential.getElement().get(diffCursor).getPath(), profileName));
                        }
                        boolean nonExtension = false;
                        if (outcome.getType().size() > 1) {
                            for (TypeRefComponent t : outcome.getType()) {
                                if (!t.getWorkingCode().equals("Reference")) {
                                    for (ElementDefinition ed : diffMatches) {
                                        if (ed != diffMatches.get(0) && !ed.getPath().endsWith(".extension")) {
                                            nonExtension = true;
                                        }
                                    }
                                }
                            }
                        }
                        int start = diffCursor;
                        while (differential.getElement().size() > diffCursor && pathStartsWith(differential.getElement().get(diffCursor).getPath(), cpath + ".")) diffCursor++;
                        if (nonExtension) {
                            throw new DefinitionException(context.formatMessage(I18nConstants._HAS_CHILDREN__AND_MULTIPLE_TYPES__IN_PROFILE_, cpath, differential.getElement().get(diffCursor).getPath(), typeCode(outcome.getType()), profileName));
                        }
                        if (outcome.hasContentReference()) {
                            ElementDefinitionResolution tgt = getElementById(srcSD, base.getElement(), outcome.getContentReference());
                            if (tgt == null)
                                throw new DefinitionException(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_REFERENCE_TO_, outcome.getContentReference()));
                            replaceFromContentReference(outcome, tgt.getElement());
                            if (tgt.getSource() != srcSD) {
                                base = tgt.getSource().getSnapshot();
                                int nbc = base.getElement().indexOf(tgt.getElement()) + 1;
                                int nbl = nbc;
                                while (nbl < base.getElement().size() && base.getElement().get(nbl).getPath().startsWith(tgt.getElement().getPath() + ".")) nbl++;
                                processPaths(indent + "  ", result, base, differential, nbc, start - 1, nbl - 1, diffCursor - 1, url, webUrl, profileName, tgt.getElement().getPath(), diffMatches.get(0).getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirectorStack(redirector, outcome, cpath), tgt.getSource());
                            } else {
                                int nbc = base.getElement().indexOf(tgt.getElement()) + 1;
                                int nbl = nbc;
                                while (nbl < base.getElement().size() && base.getElement().get(nbl).getPath().startsWith(tgt.getElement().getPath() + ".")) nbl++;
                                System.out.println("Test!");
                                processPaths(indent + "  ", result, base, differential, nbc, start, nbl - 1, diffCursor - 1, url, webUrl, profileName, tgt.getElement().getPath(), outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirectorStack(redirector, outcome, cpath), srcSD);
                            }
                        } else {
                            StructureDefinition dt = outcome.getType().size() > 1 ? context.fetchTypeDefinition("Element") : getProfileForDataType(outcome.getType().get(0), webUrl);
                            if (dt == null) {
                                throw new DefinitionException(context.formatMessage(I18nConstants.UNKNOWN_TYPE__AT_, outcome.getType().get(0), cpath));
                            }
                            contextName = dt.getUrl();
                            if (redirector.isEmpty()) {
                                processPaths(indent + "  ", result, dt.getSnapshot(), differential, 1, /* starting again on the data type, but skip the root */
                                start, dt.getSnapshot().getElement().size() - 1, diffCursor - 1, url, getWebUrl(dt, webUrl, indent), profileName, cpath, outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD);
                            } else {
                                processPaths(indent + "  ", result, dt.getSnapshot(), differential, 1, /* starting again on the data type, but skip the root */
                                start, dt.getSnapshot().getElement().size() - 1, diffCursor - 1, url, getWebUrl(dt, webUrl, indent), profileName, cpath, outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirectorStack(redirector, currentBase, cpath), srcSD);
                            }
                        }
                    }
                }
                baseCursor++;
            } else if (diffMatches.size() == 1 && (slicingDone || (!isImplicitSlicing(diffMatches.get(0), cpath) && !(diffMatches.get(0).hasSlicing() || (isExtension(diffMatches.get(0)) && diffMatches.get(0).hasSliceName()))))) {
                // one matching element in the differential
                ElementDefinition template = null;
                if (diffMatches.get(0).hasType() && "Reference".equals(diffMatches.get(0).getType().get(0).getWorkingCode()) && !isValidType(diffMatches.get(0).getType().get(0), currentBase)) {
                    throw new DefinitionException(context.formatMessage(I18nConstants.VALIDATION_VAL_ILLEGAL_TYPE_CONSTRAINT, url, diffMatches.get(0).getPath(), diffMatches.get(0).getType().get(0), currentBase.typeSummary()));
                }
                String id = diffMatches.get(0).getId();
                String lid = tail(id);
                if (lid.contains("/")) {
                    // the template comes from the snapshot of the base
                    generateIds(result.getElement(), url, srcSD.getType());
                    // this is wrong if there's more than one reslice (todo: one thing at a time)
                    String baseId = id.substring(0, id.length() - lid.length()) + lid.substring(0, lid.indexOf("/"));
                    template = getById(result.getElement(), baseId);
                } else if (diffMatches.get(0).hasType() && diffMatches.get(0).getType().size() == 1 && diffMatches.get(0).getType().get(0).hasProfile() && !"Reference".equals(diffMatches.get(0).getType().get(0).getWorkingCode())) {
                    CanonicalType p = diffMatches.get(0).getType().get(0).getProfile().get(0);
                    StructureDefinition sd = context.fetchResource(StructureDefinition.class, p.getValue());
                    if (sd == null && xver != null && xver.matchingUrl(p.getValue())) {
                        switch(xver.status(p.getValue())) {
                            case BadVersion:
                                throw new FHIRException("Reference to invalid version in extension url " + p.getValue());
                            case Invalid:
                                throw new FHIRException("Reference to invalid extension " + p.getValue());
                            case Unknown:
                                throw new FHIRException("Reference to unknown extension " + p.getValue());
                            case Valid:
                                sd = xver.makeDefinition(p.getValue());
                                generateSnapshot(context.fetchTypeDefinition("Extension"), sd, sd.getUrl(), webUrl, sd.getName());
                        }
                    }
                    if (sd != null) {
                        if (!isMatchingType(sd, diffMatches.get(0).getType(), p.getExtensionString(ToolingExtensions.EXT_PROFILE_ELEMENT))) {
                            throw new DefinitionException(context.formatMessage(I18nConstants.VALIDATION_VAL_PROFILE_WRONGTYPE2, sd.getUrl(), diffMatches.get(0).getPath(), sd.getType(), p.getValue(), diffMatches.get(0).getType().get(0).getWorkingCode()));
                        }
                        if (isGenerating(sd)) {
                            // but we check anyway
                            if (sd.getSnapshot().getElementFirstRep().isEmpty()) {
                                throw new FHIRException(context.formatMessage(I18nConstants.ATTEMPT_TO_USE_A_SNAPSHOT_ON_PROFILE__AS__BEFORE_IT_IS_GENERATED, sd.getUrl(), "Source for first element"));
                            }
                        } else if (!sd.hasSnapshot()) {
                            StructureDefinition sdb = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition());
                            if (sdb == null)
                                throw new DefinitionException(context.formatMessage(I18nConstants.UNABLE_TO_FIND_BASE__FOR_, sd.getBaseDefinition(), sd.getUrl()));
                            checkNotGenerating(sdb, "an extension base");
                            generateSnapshot(sdb, sd, sd.getUrl(), (sdb.hasUserData("path")) ? Utilities.extractBaseUrl(sdb.getUserString("path")) : webUrl, sd.getName());
                        }
                        ElementDefinition src;
                        if (p.hasExtension(ToolingExtensions.EXT_PROFILE_ELEMENT)) {
                            src = null;
                            String eid = p.getExtensionString(ToolingExtensions.EXT_PROFILE_ELEMENT);
                            for (ElementDefinition t : sd.getSnapshot().getElement()) {
                                if (eid.equals(t.getId()))
                                    src = t;
                            }
                            if (src == null)
                                throw new DefinitionException(context.formatMessage(I18nConstants.UNABLE_TO_FIND_ELEMENT__IN_, eid, p.getValue()));
                        } else
                            src = sd.getSnapshot().getElement().get(0);
                        template = src.copy().setPath(currentBase.getPath());
                        template.setSliceName(null);
                        // temporary work around
                        if (!"Extension".equals(diffMatches.get(0).getType().get(0).getCode())) {
                            template.setMin(currentBase.getMin());
                            template.setMax(currentBase.getMax());
                        }
                    }
                }
                if (template == null)
                    template = currentBase.copy();
                else
                    // some of what's in currentBase overrides template
                    template = fillOutFromBase(template, currentBase);
                ElementDefinition outcome = updateURLs(url, webUrl, template);
                outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc));
                if (res == null)
                    res = outcome;
                updateFromBase(outcome, currentBase);
                if (diffMatches.get(0).hasSliceName()) {
                    outcome.setSliceName(diffMatches.get(0).getSliceName());
                    if (!diffMatches.get(0).hasMin() && (diffMatches.size() > 1 || slicer == null || slicer.getSlicing().getRules() != SlicingRules.CLOSED) && !currentBase.hasSliceName()) {
                        if (!cpath.endsWith("xtension.value[x]")) {
                            // hack work around for problems with snapshots in official releases
                            outcome.setMin(0);
                        }
                    }
                }
                updateFromDefinition(outcome, diffMatches.get(0), profileName, trimDifferential, url, srcSD);
                removeStatusExtensions(outcome);
                // if (outcome.getPath().endsWith("[x]") && outcome.getType().size() == 1 && !outcome.getType().get(0).getCode().equals("*") && !diffMatches.get(0).hasSlicing()) // if the base profile allows multiple types, but the profile only allows one, rename it
                // outcome.setPath(outcome.getPath().substring(0, outcome.getPath().length()-3)+Utilities.capitalize(outcome.getType().get(0).getCode()));
                outcome.setSlicing(null);
                if (resultPathBase == null)
                    resultPathBase = outcome.getPath();
                else if (!outcome.getPath().startsWith(resultPathBase))
                    throw new DefinitionException(context.formatMessage(I18nConstants.ADDING_WRONG_PATH));
                result.getElement().add(outcome);
                baseCursor++;
                diffCursor = differential.getElement().indexOf(diffMatches.get(0)) + 1;
                if (diffLimit >= diffCursor && outcome.getPath().contains(".") && (isDataType(outcome.getType()) || isBaseResource(outcome.getType()) || outcome.hasContentReference())) {
                    // don't want to do this for the root, since that's base, and we're already processing it
                    if (pathStartsWith(differential.getElement().get(diffCursor).getPath(), diffMatches.get(0).getPath() + ".") && !baseWalksInto(base.getElement(), baseCursor)) {
                        if (outcome.getType().size() > 1) {
                            if (outcome.getPath().endsWith("[x]") && !diffMatches.get(0).getPath().endsWith("[x]")) {
                                String en = tail(outcome.getPath());
                                String tn = tail(diffMatches.get(0).getPath());
                                String t = tn.substring(en.length() - 3);
                                if (isPrimitive(Utilities.uncapitalize(t)))
                                    t = Utilities.uncapitalize(t);
                                // keep any additional information
                                List<TypeRefComponent> ntr = getByTypeName(outcome.getType(), t);
                                if (ntr.isEmpty())
                                    ntr.add(new TypeRefComponent().setCode(t));
                                outcome.getType().clear();
                                outcome.getType().addAll(ntr);
                            }
                            if (outcome.getType().size() > 1)
                                for (TypeRefComponent t : outcome.getType()) {
                                    if (!t.getCode().equals("Reference")) {
                                        boolean nonExtension = false;
                                        for (ElementDefinition ed : diffMatches) if (ed != diffMatches.get(0) && !ed.getPath().endsWith(".extension"))
                                            nonExtension = true;
                                        if (nonExtension)
                                            throw new DefinitionException(context.formatMessage(I18nConstants._HAS_CHILDREN__AND_MULTIPLE_TYPES__IN_PROFILE_, diffMatches.get(0).getPath(), differential.getElement().get(diffCursor).getPath(), typeCode(outcome.getType()), profileName));
                                    }
                                }
                        }
                        int start = diffCursor;
                        while (diffCursor <= diffLimit && differential.getElement().size() > diffCursor && pathStartsWith(differential.getElement().get(diffCursor).getPath(), diffMatches.get(0).getPath() + ".")) diffCursor++;
                        if (outcome.hasContentReference()) {
                            ElementDefinitionResolution tgt = getElementById(srcSD, base.getElement(), outcome.getContentReference());
                            if (tgt == null)
                                throw new DefinitionException(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_REFERENCE_TO_, outcome.getContentReference()));
                            replaceFromContentReference(outcome, tgt.getElement());
                            if (tgt.getSource() != srcSD) {
                                base = tgt.getSource().getSnapshot();
                                int nbc = base.getElement().indexOf(tgt.getElement()) + 1;
                                int nbl = nbc;
                                while (nbl < base.getElement().size() && base.getElement().get(nbl).getPath().startsWith(tgt.getElement().getPath() + ".")) nbl++;
                                processPaths(indent + "  ", result, base, differential, nbc, start - 1, nbl - 1, diffCursor - 1, url, webUrl, profileName, tgt.getElement().getPath(), diffMatches.get(0).getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirectorStack(redirector, outcome, cpath), tgt.getSource());
                            } else {
                                int nbc = base.getElement().indexOf(tgt.getElement()) + 1;
                                int nbl = nbc;
                                while (nbl < base.getElement().size() && base.getElement().get(nbl).getPath().startsWith(tgt.getElement().getPath() + ".")) nbl++;
                                processPaths(indent + "  ", result, base, differential, nbc, start - 1, nbl - 1, diffCursor - 1, url, webUrl, profileName, tgt.getElement().getPath(), diffMatches.get(0).getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirectorStack(redirector, outcome, cpath), srcSD);
                            }
                        } else {
                            StructureDefinition dt = outcome.getType().size() == 1 ? getProfileForDataType(outcome.getType().get(0), webUrl) : getProfileForDataType("Element");
                            if (dt == null)
                                throw new DefinitionException(context.formatMessage(I18nConstants._HAS_CHILDREN__FOR_TYPE__IN_PROFILE__BUT_CANT_FIND_TYPE, diffMatches.get(0).getPath(), differential.getElement().get(diffCursor).getPath(), typeCode(outcome.getType()), profileName));
                            contextName = dt.getUrl();
                            processPaths(indent + "  ", result, dt.getSnapshot(), differential, 1, /* starting again on the data type, but skip the root */
                            start, dt.getSnapshot().getElement().size() - 1, diffCursor - 1, url, getWebUrl(dt, webUrl, indent), profileName + pathTail(diffMatches, 0), diffMatches.get(0).getPath(), outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, null, new ArrayList<ElementRedirection>(), srcSD);
                        }
                    }
                }
            } else if (diffsConstrainTypes(diffMatches, cpath, typeList)) {
                int start = 0;
                int nbl = findEndOfElement(base, baseCursor);
                int ndc = differential.getElement().indexOf(diffMatches.get(0));
                ElementDefinition elementToRemove = null;
                boolean shortCut = !typeList.isEmpty() && typeList.get(0).type != null;
                // we come here whether they are sliced in the diff, or whether the short cut is used.
                if (shortCut) {
                    // in R3 (and unpatched R4, as a workaround right now...
                    if (!FHIRVersion.isR4Plus(context.getVersion()) || !newSlicingProcessing) {
                        // newSlicingProcessing is a work around for editorial loop dependency
                        // we insert a cloned element with the right types at the start of the diffMatches
                        ElementDefinition ed = new ElementDefinition();
                        ed.setPath(determineTypeSlicePath(diffMatches.get(0).getPath(), cpath));
                        for (TypeSlice ts : typeList) ed.addType().setCode(ts.type);
                        ed.setSlicing(new ElementDefinitionSlicingComponent());
                        ed.getSlicing().addDiscriminator().setType(DiscriminatorType.TYPE).setPath("$this");
                        ed.getSlicing().setRules(SlicingRules.CLOSED);
                        ed.getSlicing().setOrdered(false);
                        diffMatches.add(0, ed);
                        differential.getElement().add(ndc, ed);
                        elementToRemove = ed;
                    } else {
                        // as of R4, this changed; if there's no slice, there's no constraint on the slice types, only one the type.
                        // so the element we insert specifies no types (= all types) allowed in the base, not just the listed type.
                        // see also discussion here: https://chat.fhir.org/#narrow/stream/179177-conformance/topic/Slicing.20a.20non-repeating.20element
                        ElementDefinition ed = new ElementDefinition();
                        ed.setPath(determineTypeSlicePath(diffMatches.get(0).getPath(), cpath));
                        ed.setSlicing(new ElementDefinitionSlicingComponent());
                        ed.getSlicing().addDiscriminator().setType(DiscriminatorType.TYPE).setPath("$this");
                        ed.getSlicing().setRules(SlicingRules.CLOSED);
                        ed.getSlicing().setOrdered(false);
                        diffMatches.add(0, ed);
                        differential.getElement().add(ndc, ed);
                        elementToRemove = ed;
                    }
                }
                int ndl = findEndOfElement(differential, ndc);
                if (diffMatches.get(0).getSlicing().hasOrdered()) {
                    if (diffMatches.get(0).getSlicing().getOrdered()) {
                        throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGORDERED__TRUE, cpath, url));
                    }
                }
                if (diffMatches.get(0).getSlicing().hasDiscriminator()) {
                    if (diffMatches.get(0).getSlicing().getDiscriminator().size() != 1) {
                        throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGDISCRIMINATORCOUNT__1, cpath, url));
                    }
                    if (diffMatches.get(0).getSlicing().getDiscriminatorFirstRep().getType() != DiscriminatorType.TYPE) {
                        throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGDISCRIMINATORTYPE__TYPE, cpath, url));
                    }
                    if (!"$this".equals(diffMatches.get(0).getSlicing().getDiscriminatorFirstRep().getPath())) {
                        throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGDISCRIMINATORPATH__THIS, cpath, url));
                    }
                }
                // check the slice names too while we're at it...
                for (TypeSlice ts : typeList) {
                    if (ts.type != null) {
                        String tn = rootName(cpath) + Utilities.capitalize(ts.type);
                        if (!ts.defn.hasSliceName()) {
                            ts.defn.setSliceName(tn);
                        } else if (!ts.defn.getSliceName().equals(tn)) {
                            if (autoFixSliceNames) {
                                ts.defn.setSliceName(tn);
                            } else {
                                throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_NAME_MUST_BE__BUT_IS_, (!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath), tn, ts.defn.getSliceName()));
                            }
                        }
                        if (!ts.defn.hasType()) {
                            ts.defn.addType().setCode(ts.type);
                        } else if (ts.defn.getType().size() > 1) {
                            throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_FOR_TYPE__HAS_MORE_THAN_ONE_TYPE_, (!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath), tn, ts.defn.typeSummary()));
                        } else if (!ts.defn.getType().get(0).getCode().equals(ts.type)) {
                            throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_FOR_TYPE__HAS_WRONG_TYPE_, (!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath), tn, ts.defn.typeSummary()));
                        }
                    }
                }
                // ok passed the checks.
                // copy the root diff, and then process any children it has
                ElementDefinition e = processPaths(indent + "  ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName + pathTail(diffMatches, 0), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, null, null, redirector, srcSD);
                if (e == null)
                    throw new FHIRException(context.formatMessage(I18nConstants.DID_NOT_FIND_TYPE_ROOT_, diffMatches.get(0).getPath()));
                // now set up slicing on the e (cause it was wiped by what we called.
                e.setSlicing(new ElementDefinitionSlicingComponent());
                e.getSlicing().addDiscriminator().setType(DiscriminatorType.TYPE).setPath("$this");
                // type slicing is always closed; the differential might call it open, but that just means it's not constraining the slices it doesn't mention
                e.getSlicing().setRules(SlicingRules.CLOSED);
                e.getSlicing().setOrdered(false);
                start++;
                String fixedType = null;
                // now we process the base scope repeatedly for each instance of the item in the differential list
                for (int i = start; i < diffMatches.size(); i++) {
                    // our processing scope for the differential is the item in the list, and all the items before the next one in the list
                    if (diffMatches.get(i).getMin() > 0) {
                        if (diffMatches.size() > i + 1) {
                            throw new FHIRException(context.formatMessage(I18nConstants.INVALID_SLICING__THERE_IS_MORE_THAN_ONE_TYPE_SLICE_AT__BUT_ONE_OF_THEM__HAS_MIN__1_SO_THE_OTHER_SLICES_CANNOT_EXIST, diffMatches.get(i).getPath(), diffMatches.get(i).getSliceName()));
                        } else {
                            e.setMin(1);
                        }
                        fixedType = determineFixedType(diffMatches, fixedType, i);
                    }
                    ndc = differential.getElement().indexOf(diffMatches.get(i));
                    ndl = findEndOfElement(differential, ndc);
                    processPaths(indent + "  ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName + pathTail(diffMatches, i), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, e, null, redirector, srcSD);
                }
                if (elementToRemove != null) {
                    differential.getElement().remove(elementToRemove);
                    ndl--;
                }
                if (fixedType != null) {
                    for (Iterator<TypeRefComponent> iter = e.getType().iterator(); iter.hasNext(); ) {
                        TypeRefComponent tr = iter.next();
                        if (!tr.getCode().equals(fixedType)) {
                            iter.remove();
                        }
                    }
                }
                if (!"0".equals(e.getMax())) {
                    // check that there's a slice for each allowed types
                    Set<String> allowedTypes = getListOfTypes(e);
                    for (TypeSlice t : typeList) {
                        if (t.type != null) {
                            allowedTypes.remove(t.type);
                        } else if (t.getDefn().hasSliceName() && t.getDefn().getType().size() == 1) {
                            allowedTypes.remove(t.getDefn().getType().get(0).getCode());
                        }
                    }
                    if (!allowedTypes.isEmpty()) {
                        if (cpath.contains("xtension.value")) {
                            for (Iterator<TypeRefComponent> iter = e.getType().iterator(); iter.hasNext(); ) {
                                TypeRefComponent tr = iter.next();
                                if (allowedTypes.contains(tr.getCode())) {
                                    iter.remove();
                                }
                            }
                        // System.out.println("!!: Extension Error at "+cpath+": Allowed Types not sliced = "+allowedTypes+". !Extension!!");
                        // throw new Error("Extension Error at "+cpath+": Allowed Types not sliced = "+allowedTypes+". !Extension!!");
                        } else {
                            e.getSlicing().setRules(SlicingRules.OPEN);
                        }
                    }
                }
                // ok, done with that - next in the base list
                baseCursor = nbl + 1;
                diffCursor = ndl + 1;
            } else {
                // ok, the differential slices the item. Let's check our pre-conditions to ensure that this is correct
                if (!unbounded(currentBase) && !isSlicedToOneOnly(diffMatches.get(0)))
                    // (but you might do that in order to split up constraints by type)
                    throw new DefinitionException(context.formatMessage(I18nConstants.ATTEMPT_TO_A_SLICE_AN_ELEMENT_THAT_DOES_NOT_REPEAT__FROM__IN_, currentBase.getPath(), currentBase.getPath(), contextName, url, diffMatches.get(0).getId(), sliceNames(diffMatches)));
                if (// well, the diff has set up a slice, but hasn't defined it. this is an error
                !diffMatches.get(0).hasSlicing() && !isExtension(currentBase))
                    throw new DefinitionException(context.formatMessage(I18nConstants.DIFFERENTIAL_DOES_NOT_HAVE_A_SLICE__B_OF_____IN_PROFILE_, currentBase.getPath(), baseCursor, baseLimit, diffCursor, diffLimit, url, cpath));
                // well, if it passed those preconditions then we slice the dest.
                int start = 0;
                int nbl = findEndOfElement(base, baseCursor);
                // if (diffMatches.size() > 1 && diffMatches.get(0).hasSlicing() && differential.getElement().indexOf(diffMatches.get(1)) > differential.getElement().indexOf(diffMatches.get(0))+1) {
                ElementDefinition slicerElement;
                if (diffMatches.size() > 1 && diffMatches.get(0).hasSlicing() && (nbl > baseCursor || differential.getElement().indexOf(diffMatches.get(1)) > differential.getElement().indexOf(diffMatches.get(0)) + 1)) {
                    // there's a default set before the slices
                    int ndc = differential.getElement().indexOf(diffMatches.get(0));
                    int ndl = findEndOfElement(differential, ndc);
                    ElementDefinition e = processPaths(indent + "  ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName + pathTail(diffMatches, 0), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, null, null, redirector, srcSD);
                    if (e == null)
                        throw new FHIRException(context.formatMessage(I18nConstants.DID_NOT_FIND_SINGLE_SLICE_, diffMatches.get(0).getPath()));
                    e.setSlicing(diffMatches.get(0).getSlicing());
                    slicerElement = e;
                    start++;
                } else {
                    // we're just going to accept the differential slicing at face value
                    ElementDefinition outcome = updateURLs(url, webUrl, currentBase.copy());
                    outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc));
                    updateFromBase(outcome, currentBase);
                    if (!diffMatches.get(0).hasSlicing())
                        outcome.setSlicing(makeExtensionSlicing());
                    else
                        outcome.setSlicing(diffMatches.get(0).getSlicing().copy());
                    if (!outcome.getPath().startsWith(resultPathBase))
                        throw new DefinitionException(context.formatMessage(I18nConstants.ADDING_WRONG_PATH));
                    result.getElement().add(outcome);
                    slicerElement = outcome;
                    // differential - if the first one in the list has a name, we'll process it. Else we'll treat it as the base definition of the slice.
                    if (!diffMatches.get(0).hasSliceName()) {
                        updateFromDefinition(outcome, diffMatches.get(0), profileName, trimDifferential, url, srcSD);
                        removeStatusExtensions(outcome);
                        if (!outcome.hasContentReference() && !outcome.hasType()) {
                            throw new DefinitionException(context.formatMessage(I18nConstants.NOT_DONE_YET));
                        }
                        if (hasInnerDiffMatches(differential, currentBase.getPath(), diffCursor, diffLimit, base.getElement(), false)) {
                            if (baseHasChildren(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 (@ " + cpath + " | " + currentBase.getPath() + ")");
                            } else {
                                StructureDefinition dt = getTypeForElement(differential, diffCursor, profileName, diffMatches, outcome, webUrl);
                                contextName = dt.getUrl();
                                diffCursor++;
                                start = diffCursor;
                                while (differential.getElement().size() > diffCursor && pathStartsWith(differential.getElement().get(diffCursor).getPath(), cpath + ".")) diffCursor++;
                                diffCursor--;
                                processPaths(indent + "  ", result, dt.getSnapshot(), differential, 1, /* starting again on the data type, but skip the root */
                                start, dt.getSnapshot().getElement().size() - 1, diffCursor, url, getWebUrl(dt, webUrl, indent), profileName, cpath, outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD);
                            }
                        }
                        start++;
                    // result.getElement().remove(result.getElement().size()-1);
                    } else
                        checkExtensionDoco(outcome);
                }
                // now, for each entry in the diff matches, we're going to process the base item
                // our processing scope for base is all the children of the current path
                int ndc = diffCursor;
                int ndl = diffCursor;
                for (int i = start; i < diffMatches.size(); i++) {
                    // our processing scope for the differential is the item in the list, and all the items before the next one in the list
                    ndc = differential.getElement().indexOf(diffMatches.get(i));
                    ndl = findEndOfElement(differential, ndc);
                    /*            if (skipSlicingElement && i == 0) {
              ndc = ndc + 1;
              if (ndc > ndl)
                continue;
            }*/
                    // now we process the base scope repeatedly for each instance of the item in the differential list
                    processPaths(indent + "  ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName + pathTail(diffMatches, i), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, slicerElement, null, redirector, srcSD);
                }
                // ok, done with that - next in the base list
                baseCursor = nbl + 1;
                diffCursor = ndl + 1;
            }
        } else {
            // the item is already sliced in the base profile.
            // here's the rules
            // 1. irrespective of whether the slicing is ordered or not, the definition order must be maintained
            // 2. slice element names have to match.
            // 3. new slices must be introduced at the end
            // corallory: you can't re-slice existing slices. is that ok?
            // we're going to need this:
            String path = currentBase.getPath();
            ElementDefinition original = currentBase;
            if (diffMatches.isEmpty()) {
                if (hasInnerDiffMatches(differential, path, diffCursor, diffLimit, base.getElement(), true)) {
                    // so we just copy it in
                    ElementDefinition outcome = updateURLs(url, webUrl, currentBase.copy());
                    outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc));
                    updateFromBase(outcome, currentBase);
                    markDerived(outcome);
                    if (resultPathBase == null)
                        resultPathBase = outcome.getPath();
                    else if (!outcome.getPath().startsWith(resultPathBase))
                        throw new DefinitionException(context.formatMessage(I18nConstants.ADDING_WRONG_PATH));
                    result.getElement().add(outcome);
                    // did we implicitly step into a new type?
                    if (baseHasChildren(base, currentBase)) {
                        // not a new type here
                        processPaths(indent + "  ", result, base, differential, baseCursor + 1, diffCursor, baseLimit, diffLimit, url, webUrl, profileName, contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD);
                        baseCursor = indexOfFirstNonChild(base, currentBase, baseCursor, baseLimit);
                    } else {
                        StructureDefinition dt = getTypeForElement(differential, diffCursor, profileName, diffMatches, outcome, webUrl);
                        contextName = dt.getUrl();
                        int start = diffCursor;
                        if (differential.getElement().get(diffCursor).getPath().equals(cpath)) {
                            diffCursor++;
                        }
                        while (differential.getElement().size() > diffCursor && pathStartsWith(differential.getElement().get(diffCursor).getPath(), cpath + ".")) {
                            diffCursor++;
                        }
                        if (diffCursor > start) {
                            processPaths(indent + "  ", result, dt.getSnapshot(), differential, 1, /* starting again on the data type, but skip the root */
                            start, dt.getSnapshot().getElement().size() - 1, diffCursor - 1, url, getWebUrl(dt, webUrl, indent), profileName, cpath, outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD);
                        }
                    }
                    baseCursor++;
                } else {
                    // copy across the currentbase, and all of its children and siblings
                    while (baseCursor < base.getElement().size() && base.getElement().get(baseCursor).getPath().startsWith(path)) {
                        ElementDefinition outcome = updateURLs(url, webUrl, base.getElement().get(baseCursor).copy());
                        outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc));
                        if (!outcome.getPath().startsWith(resultPathBase))
                            throw new DefinitionException(context.formatMessage(I18nConstants.ADDING_WRONG_PATH_IN_PROFILE___VS_, profileName, outcome.getPath(), resultPathBase));
                        // so we just copy it in
                        result.getElement().add(outcome);
                        baseCursor++;
                    }
                }
            } else if (diffsConstrainTypes(diffMatches, cpath, typeList)) {
                int start = 0;
                int nbl = findEndOfElement(base, baseCursor);
                int ndc = differential.getElement().indexOf(diffMatches.get(0));
                ElementDefinition elementToRemove = null;
                boolean shortCut = (!typeList.isEmpty() && typeList.get(0).type != null) || (diffMatches.get(0).hasSliceName() && !diffMatches.get(0).hasSlicing());
                // we come here whether they are sliced in the diff, or whether the short cut is used.
                if (shortCut) {
                    // in R3 (and unpatched R4, as a workaround right now...
                    if (!FHIRVersion.isR4Plus(context.getVersion()) || !newSlicingProcessing) {
                        // newSlicingProcessing is a work around for editorial loop dependency
                        // we insert a cloned element with the right types at the start of the diffMatches
                        ElementDefinition ed = new ElementDefinition();
                        ed.setPath(determineTypeSlicePath(diffMatches.get(0).getPath(), cpath));
                        for (TypeSlice ts : typeList) ed.addType().setCode(ts.type);
                        ed.setSlicing(new ElementDefinitionSlicingComponent());
                        ed.getSlicing().addDiscriminator().setType(DiscriminatorType.TYPE).setPath("$this");
                        ed.getSlicing().setRules(SlicingRules.CLOSED);
                        ed.getSlicing().setOrdered(false);
                        diffMatches.add(0, ed);
                        differential.getElement().add(ndc, ed);
                        elementToRemove = ed;
                    } else {
                        // as of R4, this changed; if there's no slice, there's no constraint on the slice types, only one the type.
                        // so the element we insert specifies no types (= all types) allowed in the base, not just the listed type.
                        // see also discussion here: https://chat.fhir.org/#narrow/stream/179177-conformance/topic/Slicing.20a.20non-repeating.20element
                        ElementDefinition ed = new ElementDefinition();
                        ed.setPath(determineTypeSlicePath(diffMatches.get(0).getPath(), cpath));
                        ed.setSlicing(new ElementDefinitionSlicingComponent());
                        ed.getSlicing().addDiscriminator().setType(DiscriminatorType.TYPE).setPath("$this");
                        ed.getSlicing().setRules(SlicingRules.CLOSED);
                        ed.getSlicing().setOrdered(false);
                        diffMatches.add(0, ed);
                        differential.getElement().add(ndc, ed);
                        elementToRemove = ed;
                    }
                }
                int ndl = findEndOfElement(differential, ndc);
                if (diffMatches.get(0).getSlicing().hasOrdered()) {
                    if (diffMatches.get(0).getSlicing().getOrdered()) {
                        throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGORDERED__TRUE, cpath, url));
                    }
                }
                if (diffMatches.get(0).getSlicing().hasDiscriminator()) {
                    if (diffMatches.get(0).getSlicing().getDiscriminator().size() != 1) {
                        throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGDISCRIMINATORCOUNT__1, cpath, url));
                    }
                    if (diffMatches.get(0).getSlicing().getDiscriminatorFirstRep().getType() != DiscriminatorType.TYPE) {
                        throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGDISCRIMINATORTYPE__TYPE, cpath, url));
                    }
                    if (!"$this".equals(diffMatches.get(0).getSlicing().getDiscriminatorFirstRep().getPath())) {
                        throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__IN__TYPE_SLICING_WITH_SLICINGDISCRIMINATORPATH__THIS, cpath, url));
                    }
                }
                // check the slice names too while we're at it...
                for (TypeSlice ts : typeList) {
                    if (ts.type != null) {
                        String tn = rootName(cpath) + Utilities.capitalize(ts.type);
                        if (!ts.defn.hasSliceName()) {
                            ts.defn.setSliceName(tn);
                        } else if (!ts.defn.getSliceName().equals(tn)) {
                            throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_NAME_MUST_BE__BUT_IS_, (!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath), tn, ts.defn.getSliceName()));
                        }
                        if (!ts.defn.hasType()) {
                            ts.defn.addType().setCode(ts.type);
                        } else if (ts.defn.getType().size() > 1) {
                            throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_FOR_TYPE__HAS_MORE_THAN_ONE_TYPE_, (!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath), tn, ts.defn.typeSummary()));
                        } else if (!ts.defn.getType().get(0).getCode().equals(ts.type)) {
                            throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_FOR_TYPE__HAS_WRONG_TYPE_, (!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath), tn, ts.defn.typeSummary()));
                        }
                    }
                }
                // ok passed the checks.
                // copy the root diff, and then process any children it has
                ElementDefinition e = processPaths(indent + "  ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName + pathTail(diffMatches, 0), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, null, cpath, redirector, srcSD);
                if (e == null)
                    throw new FHIRException(context.formatMessage(I18nConstants.DID_NOT_FIND_TYPE_ROOT_, diffMatches.get(0).getPath()));
                // now set up slicing on the e (cause it was wiped by what we called.
                e.setSlicing(new ElementDefinitionSlicingComponent());
                e.getSlicing().addDiscriminator().setType(DiscriminatorType.TYPE).setPath("$this");
                // type slicing is always closed; the differential might call it open, but that just means it's not constraining the slices it doesn't mention
                e.getSlicing().setRules(SlicingRules.CLOSED);
                e.getSlicing().setOrdered(false);
                start++;
                String fixedType = null;
                List<BaseTypeSlice> baseSlices = findBaseSlices(base, nbl);
                // now we process the base scope repeatedly for each instance of the item in the differential list
                for (int i = start; i < diffMatches.size(); i++) {
                    String type = determineFixedType(diffMatches, fixedType, i);
                    // our processing scope for the differential is the item in the list, and all the items before the next one in the list
                    if (diffMatches.get(i).getMin() > 0) {
                        if (diffMatches.size() > i + 1) {
                            throw new FHIRException(context.formatMessage(I18nConstants.INVALID_SLICING__THERE_IS_MORE_THAN_ONE_TYPE_SLICE_AT__BUT_ONE_OF_THEM__HAS_MIN__1_SO_THE_OTHER_SLICES_CANNOT_EXIST, diffMatches.get(i).getPath(), diffMatches.get(i).getSliceName()));
                        }
                        fixedType = type;
                    }
                    ndc = differential.getElement().indexOf(diffMatches.get(i));
                    ndl = findEndOfElement(differential, ndc);
                    int sStart = baseCursor;
                    int sEnd = nbl;
                    BaseTypeSlice bs = chooseMatchingBaseSlice(baseSlices, type);
                    if (bs != null) {
                        sStart = bs.start;
                        sEnd = bs.end;
                        bs.handled = true;
                    }
                    processPaths(indent + "  ", result, base, differential, sStart, ndc, sEnd, ndl, url, webUrl, profileName + pathTail(diffMatches, i), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, e, cpath, redirector, srcSD);
                }
                if (elementToRemove != null) {
                    differential.getElement().remove(elementToRemove);
                    ndl--;
                }
                if (fixedType != null) {
                    for (Iterator<TypeRefComponent> iter = e.getType().iterator(); iter.hasNext(); ) {
                        TypeRefComponent tr = iter.next();
                        if (!tr.getCode().equals(fixedType)) {
                            iter.remove();
                        }
                    }
                }
                for (BaseTypeSlice bs : baseSlices) {
                    if (!bs.handled) {
                        // ok we gimme up a fake differential that says nothing, and run that against the slice.
                        StructureDefinitionDifferentialComponent fakeDiff = new StructureDefinitionDifferentialComponent();
                        fakeDiff.getElementFirstRep().setPath(bs.defn.getPath());
                        processPaths(indent + "  ", result, base, fakeDiff, bs.start, 0, bs.end, 0, url, webUrl, profileName + tail(bs.defn.getPath()), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, e, cpath, redirector, srcSD);
                    }
                }
                // ok, done with that - next in the base list
                baseCursor = baseSlices.get(baseSlices.size() - 1).end + 1;
                diffCursor = ndl + 1;
            // throw new Error("not done yet - slicing / types @ "+cpath);
            } else {
                // first - check that the slicing is ok
                boolean closed = currentBase.getSlicing().getRules() == SlicingRules.CLOSED;
                int diffpos = 0;
                boolean isExtension = cpath.endsWith(".extension") || cpath.endsWith(".modifierExtension");
                if (diffMatches.get(0).hasSlicing()) {
                    // it might be null if the differential doesn't want to say anything about slicing
                    // if (!isExtension)
                    // diffpos++; // if there's a slice on the first, we'll ignore any content it has
                    ElementDefinitionSlicingComponent dSlice = diffMatches.get(0).getSlicing();
                    ElementDefinitionSlicingComponent bSlice = currentBase.getSlicing();
                    if (dSlice.hasOrderedElement() && bSlice.hasOrderedElement() && !orderMatches(dSlice.getOrderedElement(), bSlice.getOrderedElement()))
                        throw new DefinitionException(context.formatMessage(I18nConstants.SLICING_RULES_ON_DIFFERENTIAL__DO_NOT_MATCH_THOSE_ON_BASE___ORDER___, summarizeSlicing(dSlice), summarizeSlicing(bSlice), path, contextName));
                    if (!discriminatorMatches(dSlice.getDiscriminator(), bSlice.getDiscriminator()))
                        throw new DefinitionException(context.formatMessage(I18nConstants.SLICING_RULES_ON_DIFFERENTIAL__DO_NOT_MATCH_THOSE_ON_BASE___DISCIMINATOR___, summarizeSlicing(dSlice), summarizeSlicing(bSlice), path, contextName));
                    if (!currentBase.isChoice() && !ruleMatches(dSlice.getRules(), bSlice.getRules()))
                        throw new DefinitionException(context.formatMessage(I18nConstants.SLICING_RULES_ON_DIFFERENTIAL__DO_NOT_MATCH_THOSE_ON_BASE___RULE___, summarizeSlicing(dSlice), summarizeSlicing(bSlice), path, contextName));
                }
                ElementDefinition outcome = updateURLs(url, webUrl, currentBase.copy());
                outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc));
                updateFromBase(outcome, currentBase);
                if (diffMatches.get(0).hasSlicing() || !diffMatches.get(0).hasSliceName()) {
                    updateFromSlicing(outcome.getSlicing(), diffMatches.get(0).getSlicing());
                    // if there's no slice, we don't want to update the unsliced description
                    updateFromDefinition(outcome, diffMatches.get(0), profileName, closed, url, srcSD);
                    removeStatusExtensions(outcome);
                } else if (!diffMatches.get(0).hasSliceName()) {
                    // because of updateFromDefinition isn't called
                    diffMatches.get(0).setUserData(GENERATED_IN_SNAPSHOT, outcome);
                }
                result.getElement().add(outcome);
                if (!diffMatches.get(0).hasSliceName()) {
                    // it's not real content, just the slice
                    diffpos++;
                }
                if (hasInnerDiffMatches(differential, cpath, diffCursor, diffLimit, base.getElement(), false)) {
                    int nbl = findEndOfElement(base, baseCursor);
                    int ndx = differential.getElement().indexOf(diffMatches.get(0));
                    int ndc = ndx + (diffMatches.get(0).hasSlicing() ? 1 : 0);
                    int ndl = findEndOfElement(differential, ndx);
                    if (nbl == baseCursor) {
                        if (base.getElement().get(baseCursor).getType().size() != 1) {
                            throw new Error(context.formatMessage(I18nConstants.DIFFERENTIAL_WALKS_INTO____BUT_THE_BASE_DOES_NOT_AND_THERE_IS_NOT_A_SINGLE_FIXED_TYPE_THE_TYPE_IS__THIS_IS_NOT_HANDLED_YET, cpath, diffMatches.get(0).toString(), base.getElement().get(baseCursor).typeSummary()));
                        }
                        StructureDefinition dt = getProfileForDataType(base.getElement().get(baseCursor).getType().get(0), webUrl);
                        if (dt == null) {
                            throw new DefinitionException(context.formatMessage(I18nConstants.UNKNOWN_TYPE__AT_, outcome.getType().get(0), diffMatches.get(0).getPath()));
                        }
                        contextName = dt.getUrl();
                        while (differential.getElement().size() > diffCursor && pathStartsWith(differential.getElement().get(diffCursor).getPath(), cpath + ".")) diffCursor++;
                        processPaths(indent + "  ", result, dt.getSnapshot(), differential, 1, ndc, dt.getSnapshot().getElement().size() - 1, ndl, url, getWebUrl(dt, webUrl, indent), profileName, cpath, outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD);
                    } else {
                        processPaths(indent + "  ", result, base, differential, baseCursor + 1, ndc, nbl, ndl, url, webUrl, profileName + pathTail(diffMatches, 0), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, false, null, null, null, srcSD);
                    }
                // throw new Error("Not done yet");
                // } else if (currentBase.getType().get(0).getCode().equals("BackboneElement") && diffMatches.size() > 0 && diffMatches.get(0).hasSliceName()) {
                } else if (currentBase.getType().get(0).getCode().equals("BackboneElement")) {
                    // We need to copy children of the backbone element before we start messing around with slices
                    int nbl = findEndOfElement(base, baseCursor);
                    for (int i = baseCursor + 1; i <= nbl; i++) {
                        outcome = updateURLs(url, webUrl, base.getElement().get(i).copy());
                        result.getElement().add(outcome);
                    }
                }
                // now, we have two lists, base and diff. we're going to work through base, looking for matches in diff.
                List<ElementDefinition> baseMatches = getSiblings(base.getElement(), currentBase);
                for (ElementDefinition baseItem : baseMatches) {
                    baseCursor = base.getElement().indexOf(baseItem);
                    outcome = updateURLs(url, webUrl, baseItem.copy());
                    updateFromBase(outcome, currentBase);
                    outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc));
                    outcome.setSlicing(null);
                    if (!outcome.getPath().startsWith(resultPathBase))
                        throw new DefinitionException(context.formatMessage(I18nConstants.ADDING_WRONG_PATH));
                    if (diffpos < diffMatches.size() && diffMatches.get(diffpos).hasSliceName() && diffMatches.get(diffpos).getSliceName().equals(outcome.getSliceName())) {
                        // if there's a diff, we update the outcome with diff
                        // no? updateFromDefinition(outcome, diffMatches.get(diffpos), profileName, closed, url);
                        // then process any children
                        int nbl = findEndOfElement(base, baseCursor);
                        int ndc = differential.getElement().indexOf(diffMatches.get(diffpos));
                        int ndl = findEndOfElement(differential, ndc);
                        // now we process the base scope repeatedly for each instance of the item in the differential list
                        processPaths(indent + "  ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName + pathTail(diffMatches, diffpos), contextPathSrc, contextPathDst, closed, contextName, resultPathBase, true, null, null, redirector, srcSD);
                        // ok, done with that - now set the cursors for if this is the end
                        baseCursor = nbl;
                        diffCursor = ndl + 1;
                        diffpos++;
                    } else {
                        result.getElement().add(outcome);
                        baseCursor++;
                        // just copy any children on the base
                        while (baseCursor < base.getElement().size() && base.getElement().get(baseCursor).getPath().startsWith(path) && !base.getElement().get(baseCursor).getPath().equals(path)) {
                            outcome = updateURLs(url, webUrl, base.getElement().get(baseCursor).copy());
                            outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc));
                            if (!outcome.getPath().startsWith(resultPathBase))
                                throw new DefinitionException(context.formatMessage(I18nConstants.ADDING_WRONG_PATH));
                            result.getElement().add(outcome);
                            baseCursor++;
                        }
                        // Lloyd - add this for test T15
                        baseCursor--;
                    }
                }
                // finally, we process any remaining entries in diff, which are new (and which are only allowed if the base wasn't closed
                boolean checkImplicitTypes = false;
                if (closed && diffpos < diffMatches.size()) {
                    // this is a problem, unless we're on a polymorhpic type and we're going to constrain a slice that actually implicitly exists
                    if (currentBase.getPath().endsWith("[x]")) {
                        checkImplicitTypes = true;
                    } else {
                        throw new DefinitionException(context.formatMessage(I18nConstants.THE_BASE_SNAPSHOT_MARKS_A_SLICING_AS_CLOSED_BUT_THE_DIFFERENTIAL_TRIES_TO_EXTEND_IT_IN__AT__, profileName, path, cpath));
                    }
                }
                if (diffpos == diffMatches.size()) {
                // Lloyd This was causing problems w/ Telus
                // diffCursor++;
                } else {
                    while (diffpos < diffMatches.size()) {
                        ElementDefinition diffItem = diffMatches.get(diffpos);
                        for (ElementDefinition baseItem : baseMatches) if (baseItem.getSliceName().equals(diffItem.getSliceName()))
                            throw new DefinitionException(context.formatMessage(I18nConstants.NAMED_ITEMS_ARE_OUT_OF_ORDER_IN_THE_SLICE));
                        outcome = updateURLs(url, webUrl, currentBase.copy());
                        // outcome = updateURLs(url, diffItem.copy());
                        outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc));
                        updateFromBase(outcome, currentBase);
                        outcome.setSlicing(null);
                        // we're in a slice, so it's only a mandatory if it's explicitly marked so
                        outcome.setMin(0);
                        if (!outcome.getPath().startsWith(resultPathBase))
                            throw new DefinitionException(context.formatMessage(I18nConstants.ADDING_WRONG_PATH));
                        result.getElement().add(outcome);
                        updateFromDefinition(outcome, diffItem, profileName, trimDifferential, url, srcSD);
                        removeStatusExtensions(outcome);
                        // --- LM Added this
                        diffCursor = differential.getElement().indexOf(diffItem) + 1;
                        if (!outcome.getType().isEmpty() && (/*outcome.getType().get(0).getCode().equals("Extension") || */
                        differential.getElement().size() > diffCursor) && outcome.getPath().contains(".")) /* && isDataType(outcome.getType())*/
                        {
                            // don't want to do this for the root, since that's base, and we're already processing it
                            if (!baseWalksInto(base.getElement(), baseCursor)) {
                                if (differential.getElement().size() > diffCursor && pathStartsWith(differential.getElement().get(diffCursor).getPath(), diffMatches.get(0).getPath() + ".")) {
                                    if (outcome.getType().size() > 1)
                                        for (TypeRefComponent t : outcome.getType()) {
                                            if (!t.getCode().equals("Reference"))
                                                throw new DefinitionException(context.formatMessage(I18nConstants._HAS_CHILDREN__AND_MULTIPLE_TYPES__IN_PROFILE_, diffMatches.get(0).getPath(), differential.getElement().get(diffCursor).getPath(), typeCode(outcome.getType()), profileName));
                                        }
                                    TypeRefComponent t = outcome.getType().get(0);
                                    if (t.getCode().equals("BackboneElement")) {
                                        int baseStart = base.getElement().indexOf(currentBase) + 1;
                                        int baseMax = baseStart + 1;
                                        while (baseMax < base.getElement().size() && base.getElement().get(baseMax).getPath().startsWith(currentBase.getPath() + ".")) baseMax++;
                                        int start = diffCursor;
                                        while (differential.getElement().size() > diffCursor && pathStartsWith(differential.getElement().get(diffCursor).getPath(), diffMatches.get(0).getPath() + ".")) diffCursor++;
                                        processPaths(indent + "  ", result, base, differential, baseStart, start - 1, baseMax - 1, diffCursor - 1, url, webUrl, profileName + pathTail(diffMatches, 0), base.getElement().get(0).getPath(), base.getElement().get(0).getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD);
                                    } else {
                                        StructureDefinition dt = getProfileForDataType(outcome.getType().get(0), webUrl);
                                        // }
                                        if (dt == null)
                                            throw new DefinitionException(context.formatMessage(I18nConstants._HAS_CHILDREN__FOR_TYPE__IN_PROFILE__BUT_CANT_FIND_TYPE, diffMatches.get(0).getPath(), differential.getElement().get(diffCursor).getPath(), typeCode(outcome.getType()), profileName));
                                        contextName = dt.getUrl();
                                        int start = diffCursor;
                                        while (differential.getElement().size() > diffCursor && pathStartsWith(differential.getElement().get(diffCursor).getPath(), diffMatches.get(0).getPath() + ".")) diffCursor++;
                                        processPaths(indent + "  ", result, dt.getSnapshot(), differential, 1, /* starting again on the data type, but skip the root */
                                        start - 1, dt.getSnapshot().getElement().size() - 1, diffCursor - 1, url, getWebUrl(dt, webUrl, indent), profileName + pathTail(diffMatches, 0), diffMatches.get(0).getPath(), outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD);
                                    }
                                }
                            }
                        }
                        // ---
                        diffpos++;
                    }
                }
                baseCursor++;
            }
        }
    }
    int i = 0;
    for (ElementDefinition e : result.getElement()) {
        i++;
        if (e.hasMinElement() && e.getMinElement().getValue() == null)
            throw new Error(context.formatMessage(I18nConstants.NULL_MIN));
    }
    return res;
}
Also used : ArrayList(java.util.ArrayList) FHIRFormatError(org.hl7.fhir.exceptions.FHIRFormatError) CanonicalType(org.hl7.fhir.r4b.model.CanonicalType) FHIRException(org.hl7.fhir.exceptions.FHIRException) StructureDefinition(org.hl7.fhir.r4b.model.StructureDefinition) TypeRefComponent(org.hl7.fhir.r4b.model.ElementDefinition.TypeRefComponent) Iterator(java.util.Iterator) StructureDefinitionDifferentialComponent(org.hl7.fhir.r4b.model.StructureDefinition.StructureDefinitionDifferentialComponent) ElementDefinitionSlicingComponent(org.hl7.fhir.r4b.model.ElementDefinition.ElementDefinitionSlicingComponent) ArrayList(java.util.ArrayList) List(java.util.List) ElementDefinition(org.hl7.fhir.r4b.model.ElementDefinition) DefinitionException(org.hl7.fhir.exceptions.DefinitionException)

Example 85 with CanonicalType

use of org.hl7.fhir.r5.model.CanonicalType in project org.hl7.fhir.core by hapifhir.

the class ProfileUtilities method genTypes.

private Cell genTypes(HierarchicalTableGenerator gen, Row r, ElementDefinition e, String profileBaseFileName, StructureDefinition profile, String corePath, String imagePath, boolean root, boolean mustSupportMode) {
    Cell c = gen.new Cell();
    r.getCells().add(c);
    if (e.hasContentReference()) {
        ElementInStructure ed = getElementByName(profile.getSnapshot().getElement(), e.getContentReference(), profile);
        if (ed == null)
            c.getPieces().add(gen.new Piece(null, translate("sd.table", "Unknown reference to %s", e.getContentReference()), null));
        else {
            if (ed.getSource() == profile) {
                c.getPieces().add(gen.new Piece(null, translate("sd.table", "See ", ed.getElement().getPath()), null));
                c.getPieces().add(gen.new Piece("#" + ed.getElement().getPath(), tail(ed.getElement().getPath()), ed.getElement().getPath()));
            } else {
                c.getPieces().add(gen.new Piece(null, translate("sd.table", "See ", ed.getElement().getPath()), null));
                c.getPieces().add(gen.new Piece(pfx(corePath, ed.getSource().getUserString("path")) + "#" + ed.getElement().getPath(), tail(ed.getElement().getPath()) + " (" + ed.getSource().getType() + ")", ed.getElement().getPath()));
            }
        }
        return c;
    }
    List<TypeRefComponent> types = e.getType();
    if (!e.hasType()) {
        if (root) {
            // we'll use base instead of types then
            StructureDefinition bsd = profile == null ? null : context.fetchResource(StructureDefinition.class, profile.getBaseDefinition());
            if (bsd != null) {
                if (bsd.hasUserData("path")) {
                    c.getPieces().add(gen.new Piece(Utilities.isAbsoluteUrl(bsd.getUserString("path")) ? bsd.getUserString("path") : imagePath + bsd.getUserString("path"), bsd.getName(), null));
                } else {
                    c.getPieces().add(gen.new Piece(null, bsd.getName(), null));
                }
            }
            return c;
        } else if (e.hasContentReference()) {
            return c;
        } else {
            ElementDefinition d = (ElementDefinition) e.getUserData(DERIVATION_POINTER);
            if (d != null && d.hasType()) {
                types = new ArrayList<ElementDefinition.TypeRefComponent>();
                for (TypeRefComponent tr : d.getType()) {
                    TypeRefComponent tt = tr.copy();
                    tt.setUserData(DERIVATION_EQUALS, true);
                    types.add(tt);
                }
            } else {
                return c;
            }
        }
    }
    boolean first = true;
    TypeRefComponent tl = null;
    for (TypeRefComponent t : types) {
        if (!mustSupportMode || allTypesMustSupport(e) || isMustSupport(t)) {
            if (first) {
                first = false;
            } else {
                c.addPiece(checkForNoChange(tl, gen.new Piece(null, ", ", null)));
            }
            tl = t;
            if (t.hasTarget()) {
                c.getPieces().add(gen.new Piece(corePath + "references.html", t.getWorkingCode(), null));
                if (!mustSupportMode && isMustSupportDirect(t) && e.getMustSupport()) {
                    c.addPiece(gen.new Piece(null, " ", null));
                    c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false);
                }
                c.getPieces().add(gen.new Piece(null, "(", null));
                boolean tfirst = true;
                for (CanonicalType u : t.getTargetProfile()) {
                    if (!mustSupportMode || allProfilesMustSupport(t.getTargetProfile()) || isMustSupport(u)) {
                        if (tfirst)
                            tfirst = false;
                        else
                            c.addPiece(gen.new Piece(null, " | ", null));
                        genTargetLink(gen, profileBaseFileName, corePath, c, t, u.getValue());
                        if (!mustSupportMode && isMustSupport(u) && e.getMustSupport()) {
                            c.addPiece(gen.new Piece(null, " ", null));
                            c.addStyledText(translate("sd.table", "This target must be supported"), "S", "white", "red", null, false);
                        }
                    }
                }
                c.getPieces().add(gen.new Piece(null, ")", null));
                if (t.getAggregation().size() > 0) {
                    c.getPieces().add(gen.new Piece(corePath + "valueset-resource-aggregation-mode.html", " {", null));
                    boolean firstA = true;
                    for (Enumeration<AggregationMode> a : t.getAggregation()) {
                        if (firstA = true)
                            firstA = false;
                        else
                            c.getPieces().add(gen.new Piece(corePath + "valueset-resource-aggregation-mode.html", ", ", null));
                        c.getPieces().add(gen.new Piece(corePath + "valueset-resource-aggregation-mode.html", codeForAggregation(a.getValue()), hintForAggregation(a.getValue())));
                    }
                    c.getPieces().add(gen.new Piece(corePath + "valueset-resource-aggregation-mode.html", "}", null));
                }
            } else if (t.hasProfile() && (!t.getWorkingCode().equals("Extension") || isProfiledType(t.getProfile()))) {
                // a profiled type
                String ref;
                boolean pfirst = true;
                for (CanonicalType p : t.getProfile()) {
                    if (!mustSupportMode || allProfilesMustSupport(t.getProfile()) || isMustSupport(p)) {
                        if (pfirst) {
                            pfirst = false;
                        } else {
                            c.addPiece(checkForNoChange(tl, gen.new Piece(null, ", ", null)));
                        }
                        ref = pkp == null ? null : pkp.getLinkForProfile(profile, p.getValue());
                        if (ref != null) {
                            String[] parts = ref.split("\\|");
                            if (parts[0].startsWith("http:") || parts[0].startsWith("https:")) {
                                // c.addPiece(checkForNoChange(t, gen.new Piece(parts[0], "<" + parts[1] + ">", t.getCode()))); Lloyd
                                c.addPiece(checkForNoChange(t, gen.new Piece(parts[0], parts[1], t.getWorkingCode())));
                            } else {
                                // c.addPiece(checkForNoChange(t, gen.new Piece((t.getProfile().startsWith(corePath)? corePath: "")+parts[0], "<" + parts[1] + ">", t.getCode())));
                                c.addPiece(checkForNoChange(t, gen.new Piece((p.getValue().startsWith(corePath + "StructureDefinition") ? corePath : "") + parts[0], parts[1], t.getWorkingCode())));
                            }
                        } else
                            c.addPiece(checkForNoChange(t, gen.new Piece((p.getValue().startsWith(corePath) ? corePath : "") + ref, t.getWorkingCode(), null)));
                        if (!mustSupportMode && isMustSupport(p) && e.getMustSupport()) {
                            c.addPiece(gen.new Piece(null, " ", null));
                            c.addStyledText(translate("sd.table", "This profile must be supported"), "S", "white", "red", null, false);
                        }
                    }
                }
            } else {
                String tc = t.getWorkingCode();
                if (Utilities.isAbsoluteUrl(tc)) {
                    StructureDefinition sd = context.fetchTypeDefinition(tc);
                    if (sd == null) {
                        c.addPiece(checkForNoChange(t, gen.new Piece(pkp.getLinkFor(corePath, tc), tc, null)));
                    } else {
                        c.addPiece(checkForNoChange(t, gen.new Piece(pkp.getLinkFor(corePath, tc), sd.getType(), null)));
                    }
                } else if (pkp != null && pkp.hasLinkFor(tc)) {
                    c.addPiece(checkForNoChange(t, gen.new Piece(pkp.getLinkFor(corePath, tc), tc, null)));
                } else {
                    c.addPiece(checkForNoChange(t, gen.new Piece(null, tc, null)));
                }
                if (!mustSupportMode && isMustSupportDirect(t) && e.getMustSupport()) {
                    c.addPiece(gen.new Piece(null, " ", null));
                    c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false);
                }
            }
        }
    }
    return c;
}
Also used : ArrayList(java.util.ArrayList) AggregationMode(org.hl7.fhir.r4b.model.ElementDefinition.AggregationMode) CanonicalType(org.hl7.fhir.r4b.model.CanonicalType) StructureDefinition(org.hl7.fhir.r4b.model.StructureDefinition) TypeRefComponent(org.hl7.fhir.r4b.model.ElementDefinition.TypeRefComponent) Piece(org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Piece) ElementDefinition(org.hl7.fhir.r4b.model.ElementDefinition) Cell(org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Cell)

Aggregations

CanonicalType (org.hl7.fhir.r4.model.CanonicalType)45 CanonicalType (org.hl7.fhir.r5.model.CanonicalType)37 ArrayList (java.util.ArrayList)27 CanonicalType (org.hl7.fhir.r4b.model.CanonicalType)19 TypeRefComponent (org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent)14 StructureDefinition (org.hl7.fhir.r5.model.StructureDefinition)13 CommaSeparatedStringBuilder (org.hl7.fhir.utilities.CommaSeparatedStringBuilder)12 Test (org.junit.jupiter.api.Test)12 List (java.util.List)10 FHIRException (org.hl7.fhir.exceptions.FHIRException)9 ElementDefinition (org.hl7.fhir.r5.model.ElementDefinition)9 HashMap (java.util.HashMap)7 HashSet (java.util.HashSet)7 Extension (org.hl7.fhir.r4.model.Extension)7 Library (org.hl7.fhir.r4.model.Library)7 StringType (org.hl7.fhir.r4.model.StringType)6 XhtmlNode (org.hl7.fhir.utilities.xhtml.XhtmlNode)6 FHIRFormatError (org.hl7.fhir.exceptions.FHIRFormatError)5 Bundle (org.hl7.fhir.r4.model.Bundle)5 IdType (org.hl7.fhir.r4.model.IdType)5