Merge remote-tracking branch 'origin/master'

This commit is contained in:
Grahame Grieve 2023-02-01 14:49:19 +11:00
commit 4a79e89f62
8 changed files with 131 additions and 6 deletions

View File

@ -43,7 +43,7 @@ correct implementation of the core FHIR specification that it implements.
### Prerequisites
This project uses [Java](https://www.java.com) (minumum version 11), [Apache Maven](http://maven.apache.org), and [Lombok](https://projectlombok.org/) to build. You can find detailed instructions on setting up this project in your IDE [here](https://hl7.github.io/docs/core/ide).
This project uses [Java](https://www.java.com) (minumum version 11), [Apache Maven](http://maven.apache.org), and [Lombok](https://projectlombok.org/) to build. You can find detailed instructions on setting up this project in your IDE [here](https://hl7.github.io/docs/core/getting-started).
### Build Commands

View File

@ -1,7 +1,12 @@
## Validator Changes
* no changes
* Fix for NPE rendering resources
## Other code changes
* no changes
* XHTML processing: Cater for "." in XML element and attribute names
* Handle R3 encoding of primitive values when validating profiles
* Improve error messaging when validating StructureDefinition
* Temporary Support for MedicationStatement in R5
* Rework Package API to allow for authentication on package servers
* Structure mapping now finds source Structure Definition by URI and sets ParserBase logical property appropriately.

View File

@ -299,6 +299,8 @@ public interface IWorkerContext {
String formatMessage(String theMessage, Object... theMessageArguments);
String formatMessagePlural(Integer pl, String theMessage, Object... theMessageArguments);
void setValidationMessageLanguage(Locale locale);
public class ValidationResult {

View File

@ -575,7 +575,7 @@ public class FHIRPathEngine {
}
private FHIRException makeExceptionPlural(Integer num, ExpressionNode holder, String constName, Object... args) {
String fmt = worker.formatMessage(constName, args);
String fmt = worker.formatMessagePlural(num, constName, args);
if (location != null) {
fmt = fmt + " "+worker.formatMessage(I18nConstants.FHIRPATH_LOCATION, location);
}

View File

@ -96,7 +96,7 @@ public class FFHIRPathHostServices implements FHIRPathEngine.IEvaluationContext
@Override
public ValueSet resolveValueSet(Object appContext, String url) {
throw new Error("Not Implemented Yet");
return structureMapUtilities.getWorker().fetchResource(ValueSet.class, url);
}
}

View File

@ -0,0 +1,31 @@
package org.hl7.fhir.r5.utils.structuremap;
import java.io.IOException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.context.SimpleWorkerContext;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.test.utils.TestingUtilities;
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
class FFHIRPathHostServicesTest {
static private SimpleWorkerContext context;
@BeforeAll
static public void setUp() throws Exception {
FilesystemPackageCacheManager pcm = new org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager(false);
context = TestingUtilities.getWorkerContext(pcm.loadPackage("hl7.fhir.r4.core", "4.0.1"));
}
@Test
public void testrResolveValueSet() throws IOException, FHIRException {
StructureMapUtilities scu = new StructureMapUtilities(context);
FFHIRPathHostServices fphs = new FFHIRPathHostServices(scu);
ValueSet v = fphs.resolveValueSet(null, "http://hl7.org/fhir/ValueSet/FHIR-version");
Assertions.assertNotNull(v);
Assertions.assertEquals("http://hl7.org/fhir/ValueSet/FHIR-version", v.getUrl());
}
}

View File

@ -36,6 +36,7 @@ import org.hl7.fhir.r5.elementmodel.Element;
import org.hl7.fhir.r5.elementmodel.Manager;
import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat;
import org.hl7.fhir.r5.elementmodel.ObjectConverter;
import org.hl7.fhir.r5.elementmodel.ParserBase;
import org.hl7.fhir.r5.elementmodel.SHCParser;
import org.hl7.fhir.r5.formats.FormatUtilities;
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
@ -623,10 +624,15 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
public org.hl7.fhir.r5.elementmodel.Element transform(byte[] source, FhirFormat cntType, String mapUri) throws FHIRException, IOException {
List<Base> outputs = new ArrayList<>();
StructureMapUtilities scu = new StructureMapUtilities(context, new TransformSupportServices(outputs, mapLog, context));
org.hl7.fhir.r5.elementmodel.Element src = Manager.parseSingle(context, new ByteArrayInputStream(source), cntType);
StructureMap map = context.fetchResource(StructureMap.class, mapUri);
if (map == null) throw new Error("Unable to find map " + mapUri + " (Known Maps = " + context.listMapUrls() + ")");
org.hl7.fhir.r5.elementmodel.Element resource = getTargetResourceFromStructureMap(map);
StructureDefinition sourceSD = getSourceResourceFromStructureMap(map);
ParserBase parser = Manager.makeParser(context, cntType);
if (sourceSD.getKind() == StructureDefinition.StructureDefinitionKind.LOGICAL) {
parser.setLogical(sourceSD);
}
org.hl7.fhir.r5.elementmodel.Element src = parser.parseSingle(new ByteArrayInputStream(source));
scu.transform(null, src, map, resource);
resource.populatePaths(null);
return resource;
@ -655,6 +661,39 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP
return Manager.build(getContext(), structureDefinition);
}
private StructureDefinition getSourceResourceFromStructureMap(StructureMap map) {
StructureMap.StructureMapGroupComponent g = map.getGroup().get(0);
String type = null;
for (StructureMap.StructureMapGroupInputComponent inp : g.getInput()) {
if (inp.getMode() == StructureMap.StructureMapInputMode.SOURCE)
if (type != null)
throw new DefinitionException("This engine does not support multiple source inputs");
else
type = inp.getType();
}
String sourceTypeUrl = null;
for (StructureMap.StructureMapStructureComponent component : map.getStructure()) {
if (component.getMode() == StructureMap.StructureMapModelMode.SOURCE
&& component.getAlias().equalsIgnoreCase(type)) {
sourceTypeUrl = component.getUrl();
break;
}
}
StructureDefinition structureDefinition = null;
for (StructureDefinition sd : this.context.fetchResourcesByType(StructureDefinition.class)) {
if (sd.getUrl().equalsIgnoreCase(sourceTypeUrl)) {
structureDefinition = sd;
break;
}
}
if (structureDefinition == null) throw new FHIRException("Unable to find StructureDefinition for source type ('" + sourceTypeUrl + "')");
return structureDefinition;
}
public Resource generate(String source, String version) throws FHIRException, IOException, EOperationOutcome {
Content cnt = igLoader.loadContent(source, "validate", false);

View File

@ -1,6 +1,7 @@
package org.hl7.fhir.r5.test;
import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.fail;
import java.io.*;
@ -10,6 +11,7 @@ import java.util.stream.Stream;
import javax.xml.parsers.ParserConfigurationException;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.r5.context.ContextUtilities;
import org.hl7.fhir.r5.context.SimpleWorkerContext;
import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat;
@ -25,7 +27,9 @@ import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.xml.XMLUtil;
import org.hl7.fhir.validation.ValidationEngine;
import org.hl7.fhir.validation.instance.InstanceValidatorFactory;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
@ -123,4 +127,48 @@ public class StructureMappingTests {
}
assertTrue(msg, Utilities.noString(msg));
}
@Test
void testTransformLogicalSource() throws Exception {
String map = "map \"http://github.com/hapifhir/org.hl7.fhir.core/org.hl7.fhir.r4.tests/cda2qr\" = \"cda2qr\"\n"
+ "\n"
+ "uses \"http://hl7.org/fhir/StructureDefinition/QuestionnaireResponse\" alias QuestionnaireResponse as target\n"
+ "uses \"http://hl7.org/fhir/cdatest/StructureDefinition/ClinicalDocument\" alias ClinicalDocument as source\n"
+ "\n"
+ "group ClinicalDocument(source src : ClinicalDocument, target tgt : QuestionnaireResponse) {\n"
+ " src -> tgt.status = 'in-progress' \"code\";\n"
+ "}";
StructureMap r = null;
try {
r = new StructureMapUtilities(context).parse(map, "cda2qr");
context.cacheResource(r);
byte[] byteSource = "{}".getBytes();
org.hl7.fhir.r5.elementmodel.Element element = validationEngine.transform(byteSource, FhirFormat.JSON, r.getUrl());
Assertions.assertNotNull(element);
} finally {
context.dropResource(r);
}
}
@Test
void testGetSourceResourceFromStructureMapDefinitionException() {
StructureMap r = new StructureMap().setUrl("testGetSourceResourceFromStructureMapDefinitionException");
StructureMap.StructureMapGroupComponent g = r.addGroup();
g.addInput().setMode(StructureMap.StructureMapInputMode.SOURCE).setType("input");
g.addInput().setMode(StructureMap.StructureMapInputMode.SOURCE).setType("input");
r.addStructure()
.setMode(StructureMap.StructureMapModelMode.TARGET)
.setUrl("testGetSourceResourceFromStructureMapDefinitionExceptionTarget");
context.cacheResource(r);
StructureDefinition structureDefinition = new StructureDefinition().setUrl("testGetSourceResourceFromStructureMapDefinitionExceptionTarget");
structureDefinition.getSnapshot().addElement().setPath("testGetSourceResourceFromStructureMapDefinitionExceptionTarget");
context.cacheResource(structureDefinition);
byte[] byteSource = "testGetSourceResourceFromStructureMapDefinitionException".getBytes();
DefinitionException thrown = assertThrows(
DefinitionException.class,
() -> validationEngine.transform(byteSource, FhirFormat.JSON, r.getUrl()),
"Expected transform() to throw DefinitionException"
);
context.dropResource(r);
context.dropResource(structureDefinition);
assertTrue(thrown.getMessage().contentEquals("This engine does not support multiple source inputs"));
}
}