Mentions légales du service

Skip to content
Snippets Groups Projects
Commit 40caf215 authored by Achraf Achkari's avatar Achraf Achkari
Browse files

Merge branch 'develop' into 'master'

[GOC-247] Fix cardinality processing and use extended element provided in BBR...

See merge request !36
parents 023713e4 16fd26c5
No related branches found
No related tags found
3 merge requests!38Master,!37Master,!36[GOC-247] Fix cardinality processing and use extended element provided in BBR...
Pipeline #658172 canceled
Showing
with 1615 additions and 3475 deletions
# Define templates
include:
- project: 'gazelle/private/gitlab-ci-templates'
file: 'extends.yaml'
file: 'extends-v2.yaml'
ref: 'master'
# Define stages
stages:
- build
- postbuild
- predeploy
- deploy
- tests
- test
- publish
- release
- upgrade
- cleanup
- clean
# Define global variables
variables:
......@@ -22,27 +23,56 @@ variables:
P_MAVEN_IMAGE_TAG: "3.6.3-jdk-11-slim"
# Define jobs
code:
compile/unit-test:
stage: build
extends:
- .buildCodeForJavaWithPostgresql
- .buildJavaMavenTest
variables:
P_MAVEN_EXTRA_ARGS: "-DskipIT=true"
P_MAVEN_TEST_SKIP: "true"
MAVEN_PHASE: "clean install"
P_MAVEN_EXTRA_ARGS: "-DskipITs"
quality:
stage: tests
package:
stage: build
extends:
- .buildJavaMavenPackage
needs:
- job: compile/unit-test
artifacts: true
variables:
P_MAVEN_EXTRA_ARGS: "-DskipTests"
integration-tests:
stage: test
extends:
- .testJavaMavenIntegrationTests
needs:
- job: compile/unit-test
artifacts: false
allow_failure: true
static-analysis:
stage: test
extends:
- .testQualityForJavaWithSonarqube
- .testJavaMavenSonarAnalysis
needs:
- job: compile/unit-test
artifacts: true
variables:
P_MAVEN_IMAGE_TAG: "3.6.3-jdk-11"
P_MAVEN_TEST_SKIP: "true"
P_MAVEN_EXTRA_ARGS: "-Psonar -DskipTests"
install-cache-repo:
stage: publish
extends:
- .publishJavaMavenInstall
needs:
- job: package
artifacts: false
variables:
P_MAVEN_EXTRA_ARGS: "-DskipTests"
release/code:
stage: release
extends:
- .releaseCodeForJava
variables:
P_MAVEN_EXTRA_ARGS: "-DskipIT=true"
P_MAVEN_TEST_SKIP: "true"
P_MAVEN_PROFIL: "release"
\ No newline at end of file
- .releaseCodeForJava
\ No newline at end of file
......@@ -25,9 +25,6 @@ public abstract class ChoiceDefinitionProcessorImpl implements ChoiceDefinitionP
this.processMinimumMultiplicity(t.getMinimumMultiplicity());
this.processContains(ChoiceDefinitionUtil.getContains(t));
this.processItem(t.getItem());
//Comment next line to disable processing of the unsported HL7 choices specs
//this.processPredicates(ChoiceDefinitionUtil.getElements(t));
}
}
......@@ -72,6 +69,7 @@ public abstract class ChoiceDefinitionProcessorImpl implements ChoiceDefinitionP
}
@Override
@Deprecated(since = "3.1.0", forRemoval = true)
public void processPredicates(List<RuleDefinition> elements) {
// to be overrided if needed to
}
......
......@@ -189,6 +189,7 @@ public class ChoiceDefinitionAnalyzer extends ChoiceDefinitionProcessorImpl {
* NOTICE: this method does not process numbered predicates due to a lack of functional specifications for the CDA
* @param elements elements in the ChoiceDefinition
*/
@Deprecated(since = "3.1.0", forRemoval = true)
@Override
public void processPredicates(List<RuleDefinition> elements){
......@@ -381,7 +382,7 @@ public class ChoiceDefinitionAnalyzer extends ChoiceDefinitionProcessorImpl {
}
public List<List<OwnedRule>> generateSubRuleOfElements(List<RuleDefinition> elements){
private List<List<OwnedRule>> generateSubRuleOfElements(List<RuleDefinition> elements){
List<List<OwnedRule>> rules = new ArrayList<>();
log.info("processing {} element in choices", Integer.valueOf(elements.size()));
for(RuleDefinition element:elements){
......@@ -416,7 +417,7 @@ public class ChoiceDefinitionAnalyzer extends ChoiceDefinitionProcessorImpl {
return rules;
}
public List<OwnedRule> generateRulesOfAssertionElements(RuleDefinition element){
private List<OwnedRule> generateRulesOfAssertionElements(RuleDefinition element){
String test = AssertUtil.extractAssertFromName(element.getName());
if(test == null){
ProblemHandler.handleRuleDefinitionError((RuleDefinition)element.getParentObject(),
......
......@@ -15,7 +15,6 @@ import net.ihe.gazelle.tempmodel.dpath.utils.DPathExtractor;
import net.ihe.gazelle.tempmodel.org.decor.art.behavior.HasItem;
import net.ihe.gazelle.tempmodel.org.decor.art.model.*;
import net.ihe.gazelle.tempmodel.org.decor.art.utils.*;
import org.eclipse.uml2.uml.DataType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -141,19 +140,18 @@ public class RuleDefinitionAnalyzer extends RuleDefinitionProcessorImpl {
AnalyzerEnum.RULE_DEF_GENERAL_PROCESS.getValue());
return;
}
this.currentPackagedElement = (PackagedElement) objects[0];
this.selectedRuleDefinition = ruleDefinition;
Object parentRule = this.selectedRuleDefinition.getParentObject();
if(parentRule instanceof ChoiceDefinition){
this.generateDTDistinguisher = (RuleDefinitionDistinguisherUtil.elementsShouldBeDistinguisedWithDT((ChoiceDefinition) parentRule));
}
if (objects.length > 1) {
this.ignoreTemplateIdRequirements = (Boolean) objects[1];
}
if (this.ignoreTemplateIdRequirements.booleanValue() && this.selectedRuleDefinition.getName() != null &&
(this.selectedRuleDefinition.getName().matches(".*:templateId") || this.selectedRuleDefinition.getName().matches("templateId"))) {
this.selectedRuleDefinition = ruleDefinition;
boolean isTemplateId = (this.selectedRuleDefinition.getName().matches(".*:templateId") || this.selectedRuleDefinition.getName().matches("templateId"));
if (this.ignoreTemplateIdRequirements.booleanValue() && this.selectedRuleDefinition.getName() != null && isTemplateId) {
return;
}
this.currentPackagedElement = (PackagedElement) objects[0];
if(!isTemplateId){
this.generateDTDistinguisher = (RuleDefinitionDistinguisherUtil.elementShouldBeDistinguisedByDT(this.selectedRuleDefinition, this.selectedRuleDefinition.getParentObject()));
}
// catch error in numbered predicates
if (!RuleDefinitionProblemUtil.verifyIfRuleDefinitionIsTreatable(this.selectedRuleDefinition)) {
String name = selectedRuleDefinition != null ? selectedRuleDefinition.getName() : null;
......@@ -423,11 +421,6 @@ public class RuleDefinitionAnalyzer extends RuleDefinitionProcessorImpl {
@UsedByArtDecor
@Override
public void processMinimumMultiplicity(Integer minimumMultiplicity) {
// TODO: 23/12/2021 Highly need to be reviewed
// if (this.ignoreMinCardinality()) {
// // this is the case where the RuleDefinition is included in a choice
// return;
// }
if (checkIfConstraintCanBeGeneratedForMinimumMultiplicity(minimumMultiplicity, this.selectedRuleDefinition)) {
if (!(this.selectedRuleDefinition.getParentObject() instanceof TemplateDefinition)) {
fulfillOwnedRuleForConstraintGenerator((new RDMinimumMultiplicityAnalyzer(this.generateDTDistinguisher)), this.currentPackagedElement, OwnedRuleKind.CARDINALITY,
......@@ -536,9 +529,6 @@ public class RuleDefinitionAnalyzer extends RuleDefinitionProcessorImpl {
if (constraintGenerator == null) {
return;
}
// if(this.generateDTDistinguisher && constraintGenerator instanceof RDDatatypeAnalyzer){
// return;
// }
OwnedRule ownedRule = OwnedRuleUtil.initOwnedRule();
ownedRule.setConstrainedElement(pe.getId());
String specification = constraintGenerator.generateOCLConstraint(this.selectedRuleDefinition);
......@@ -579,6 +569,7 @@ public class RuleDefinitionAnalyzer extends RuleDefinitionProcessorImpl {
* @param pe temporary package used to grab all sub elements rules
* @return returns a list of ownedRules for the ruleDefinition itself and sub elements
*/
@Deprecated(since = "3.1.0", forRemoval = true)
public List<OwnedRule> processAndReturn(RuleDefinition ruleDefinition, PackagedElement pe){
if(pe == null){
pe = PackagedElementUtil.initPackagedElement();
......@@ -589,7 +580,7 @@ public class RuleDefinitionAnalyzer extends RuleDefinitionProcessorImpl {
if(pe.getOwnedRule().size() == 0){
return null;
};
}
//Clean TAML
for(OwnedRule or:pe.getOwnedRule()){
......
package net.ihe.gazelle.tempgen.action;
import net.ihe.gazelle.tempmodel.decor.dt.utils.DTUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -24,12 +25,15 @@ public class UMLElementsManager {
* @param indexParam index
* @return int
*/
public int getMaxAttribute(DParent cdaPath, Integer indexParam){
public int getMaxAttribute(DParent cdaPath, Integer indexParam, String parentDatatype){
Integer index = indexParam;
if (index == null){
index = Integer.valueOf(cdaPath.size() - 1);
}
String typeName = (new PathManager()).findPathTypeName(cdaPath, index.intValue() -1);
if(parentDatatype != null && DTUtils.constrainedDTIsAnExtension(parentDatatype, typeName)){
typeName = parentDatatype.replace("_","");
}
if (cdaPath.get(index.intValue()) != null) {
String attrName = cdaPath.get(index.intValue()).getName();
return UMLLoader.getMaxAttribute(typeName, attrName);
......@@ -37,6 +41,10 @@ public class UMLElementsManager {
log.error("The requested index ( {} ) is out of bound regarding the cdaPath", index);
return -1;
}
public int getMaxAttribute(DParent cdaPath, Integer indexParam){
return getMaxAttribute(cdaPath, indexParam, null);
}
public int getMinAttribute(DParent cdaPath, Integer indexParam){
Integer index = indexParam;
......
......@@ -4,11 +4,14 @@ import net.ihe.gazelle.tempgen.action.OCLCleaner;
import net.ihe.gazelle.tempgen.action.OCLGenerator;
import net.ihe.gazelle.tempgen.action.OwnedRuleManager;
import net.ihe.gazelle.tempgen.action.UMLElementsManager;
import net.ihe.gazelle.tempmodel.decor.dt.utils.DTUtils;
import net.ihe.gazelle.tempmodel.dpath.model.DParent;
import net.ihe.gazelle.tempmodel.dpath.utils.DPathExtractor;
import net.ihe.gazelle.tempmodel.org.decor.art.model.RuleDefinition;
import net.ihe.gazelle.tempmodel.org.decor.art.utils.RuleDefinitionUtil;
import javax.xml.namespace.QName;
/**
*
* @author Abderrazek Boufahja
......@@ -50,8 +53,17 @@ public class RDMaximumMultiplicityAnalyzer implements ConstraintGenerator{
}
else {
res = contextRule + "->forAll(";
int max = (new UMLElementsManager()).getMaxAttribute(RuleDefinitionUtil.getDParentOfRuleDefinition(ruleDefinition), null);
if (max == 1){
int max = 0;
UMLElementsManager umlElementsManager = new UMLElementsManager();
if(ruleDefinition.getParentObject() instanceof RuleDefinition &&
((RuleDefinition) ruleDefinition.getParentObject()).getDatatype() != null){
String parentDt = ((RuleDefinition) ruleDefinition.getParentObject()).getDatatype().getLocalPart();
max = umlElementsManager.getMaxAttribute(RuleDefinitionUtil.getDParentOfRuleDefinition(ruleDefinition), null, parentDt);
}
else{
max = umlElementsManager.getMaxAttribute(RuleDefinitionUtil.getDParentOfRuleDefinition(ruleDefinition), null);
}
if (max == 0){
res = res + RuleDefinitionUtil.getRealNameOfRuleDefinition(ruleDefinition) + ".oclIsUndefined())";
}
else{
......
......@@ -5,6 +5,8 @@ import net.ihe.gazelle.svs.RetrieveValueSetResponseType;
import net.ihe.gazelle.tempapi.impl.ValueSetConceptProcessorImpl;
import net.ihe.gazelle.tempmodel.org.decor.art.model.ValueSetConcept;
import java.util.List;
/**
*
* @author Abderrazek Boufahja
......@@ -15,23 +17,18 @@ public class ValueSetConceptProc extends ValueSetConceptProcessorImpl {
protected RetrieveValueSetResponseType currentRetrieveValueSetResponseType;
protected net.ihe.gazelle.datatypes.CE concept;
protected List<CE> conceptList;
@Override
public void process(ValueSetConcept t, Object... objects) {
this.currentRetrieveValueSetResponseType = (RetrieveValueSetResponseType) objects[0];
if (this.currentRetrieveValueSetResponseType == null || this.currentRetrieveValueSetResponseType.getValueSet() == null ||
this.currentRetrieveValueSetResponseType.getValueSet().getConceptList() == null ||
this.currentRetrieveValueSetResponseType.getValueSet().getConceptList().isEmpty() ||
this.currentRetrieveValueSetResponseType.getValueSet().getConceptList().get(0) == null
) {
return;
}
if (t == null) {
return;
}
this.conceptList = (java.util.List<net.ihe.gazelle.datatypes.CE> ) objects[1];
this.concept = new CE();
super.process(t, objects);
this.currentRetrieveValueSetResponseType.getValueSet().getConceptList().get(0).getConcept().add(concept);
this.conceptList.add(concept);
}
@Override
......
package net.ihe.gazelle.tempgen.valueset.action;
import java.io.File;
import java.io.IOException;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -47,17 +47,27 @@ public final class ValueSetExtractor {
}
for (ValueSet valueSet : decor.getTerminology().getValueSet()) {
RetrieveValueSetResponseType resp = new RetrieveValueSetResponseType();
List<net.ihe.gazelle.datatypes.CE> concepts = new ArrayList<>(10000);
VSImplProvider vsImplProvider = new VSImplProvider();
ValueSetVisitor.INSTANCE.visitAndProcess(valueSet, vsImplProvider, resp);
ValueSetVisitor.INSTANCE.visitAndProcess(valueSet, vsImplProvider, resp, concepts);
if(resp.getValueSet().getConceptList() != null && !resp.getValueSet().getConceptList().isEmpty()){
resp.getValueSet().getConceptList().get(0).getConcept().addAll(concepts);
}
String respString = SVSMarshaller.marshall(resp);
if (respString.contains("Concept ")) {
processedValueSets.add(valueSet.getId());
String filepath = createFilePath(outputFile, valueSet);
File out = new File(filepath);
if (out.exists()) {
log.info(valueSet.getId() + "already used !");
log.info("{} already used !", valueSet.getId());
}
else{
try(FileOutputStream f = new FileOutputStream(out)){
BufferedOutputStream bos = new BufferedOutputStream(f);
bos.write(respString.getBytes());
bos.close();
}
}
FileReadWrite.printDoc(respString, out.getAbsolutePath());
}
else {
ProblemHandler.handleError("There are no concept in the declared valueset : " + valueSet.getId(),
......
......@@ -12,6 +12,9 @@ import net.ihe.gazelle.svs.ValueSetResponseType;
import net.ihe.gazelle.tempgen.valueset.action.ValueSetConceptProc;
import net.ihe.gazelle.tempmodel.org.decor.art.model.ValueSetConcept;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author Abderrazek Boufahja
......@@ -28,10 +31,11 @@ public class ValueSetConceptProcTest extends ValueSetConceptProc {
public void testProcess() {
ValueSetConcept vsc = new ValueSetConcept();
RetrieveValueSetResponseType currentRetrieveValueSetResponseType = new RetrieveValueSetResponseType();
List<CE> conceptList = new ArrayList<>();
currentRetrieveValueSetResponseType.setValueSet(new ValueSetResponseType());
currentRetrieveValueSetResponseType.getValueSet().getConceptList().add(new ConceptListType());
this.process(vsc, new Object[] {currentRetrieveValueSetResponseType});
assertTrue(this.currentRetrieveValueSetResponseType.getValueSet().getConceptList().get(0).getConcept()!= null);
this.process(vsc, new Object[] {currentRetrieveValueSetResponseType, conceptList});
assertTrue(this.conceptList!= null);
}
@Test
......
......@@ -13,6 +13,7 @@ import org.slf4j.LoggerFactory;
import javax.xml.namespace.QName;
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;
/**
* @author Abderrazek Boufahja
......@@ -121,14 +122,21 @@ public class RuleDefinitionDistinguisherUtil {
return null;
}
public static Boolean elementsShouldBeDistinguisedWithDT(ChoiceDefinition choiceDefinition){
Set<String> names = new HashSet<>();
int count = 0;
for(RuleDefinition rd : ChoiceDefinitionUtil.getElements(choiceDefinition)){
names.add(RuleDefinitionUtil.getRealNameOfRuleDefinition(rd));
count++;
public static Boolean elementShouldBeDistinguisedByDT(RuleDefinition element, Object parent) {
List<RuleDefinition> nameOfElementsInParent = null;
if(parent instanceof RuleDefinition){
nameOfElementsInParent = RuleDefinitionUtil.getAllEffectiveElements((RuleDefinition) parent);
}
return Boolean.valueOf(names.size() != count);
else if(parent instanceof ChoiceDefinition){
nameOfElementsInParent = ChoiceDefinitionUtil.getElements((ChoiceDefinition) parent);
}
else {
return Boolean.FALSE;
}
return Boolean.valueOf(nameOfElementsInParent.stream()
.map(RuleDefinitionUtil::getRealNameOfRuleDefinition)
.filter(name -> name.equals(RuleDefinitionUtil.getRealNameOfRuleDefinition(element)))
.count() > 1);
}
}
......@@ -41,6 +41,20 @@ public class RuleDefinitionUtil {
return elements;
}
/**
* Flatten the rule definition and extract choices, to get all possible elements
* @param ruleDefinition the rule definition to flatten
* @return list of ruledefinitions
*/
public static List<RuleDefinition> getAllEffectiveElements(RuleDefinition ruleDefinition){
List<RuleDefinition> elements = getElements(ruleDefinition);
List<ChoiceDefinition> choices = getChoices(ruleDefinition);
for(ChoiceDefinition choice : choices){
elements.addAll(ChoiceDefinitionUtil.getElements(choice));
}
return elements;
}
public static List<ChoiceDefinition> getChoices(RuleDefinition ruleDefinition) {
List<ChoiceDefinition> elements = new ArrayList<>();
if (ruleDefinition != null) {
......
......@@ -22,6 +22,14 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3</version>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
......
......@@ -8,6 +8,7 @@ import net.ihe.gazelle.lib.hl7templatespackager.peripherals.FolderCreatorImpl;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
......@@ -22,7 +23,7 @@ public class ArchetypeInstantiatorMaven implements ArchetypeInstantiator {
private static org.slf4j.Logger log = LoggerFactory.getLogger(ArchetypeInstantiatorMaven.class);
//this is supposed to be the version of the packager artifact. It is for now used as artifact version. See what we will use
private static final String gocVersion = "3.1.0";
private static String gocVersion = null;
private static final String CD_COMMAND = "cd \"";
private static final String REPOSITORY = "https://gazelle.ihe.net/nexus/content/groups/public/";
......@@ -53,6 +54,9 @@ public class ArchetypeInstantiatorMaven implements ArchetypeInstantiator {
this.gocLogger = gocLogger;
this.processExecutor = processExecutor;
this.valueSetExtractor = valueSetExtractor;
if(gocVersion == null){
gocVersion = getGOCVersion();
}
}
/**
......@@ -194,6 +198,34 @@ public class ArchetypeInstantiatorMaven implements ArchetypeInstantiator {
}
}
private String getGOCVersion(){
String version = ArchetypeInstantiatorMaven.class.getPackage().getImplementationVersion();
if(version == null){
version = System.getProperty("GOC_VERSION");
if(version == null){
log.error("Could not find GOC version, trying to get it from latest release in nexus");
}
version = getLatestGOCVersion();
}
return version;
}
//Get latest GOC Version from nexus
private String getLatestGOCVersion(){
String command = "curl \"https://gazelle.ihe.net/nexus/service/local/repositories/releases/index_content/?groupIdHint=net.ihe.gazelle&artifactIdHint=gazelle-objects-checker\" 2>&1 " +
" | grep \"version\" | grep -o -e \"[0-9.]*\" | head -n 1";
List<String> output = null;
try {
output = processExecutor.executeProcessAndReturn(command);
if(output != null && output.size()>0){
return output.get(0);
}
} catch (IOException e) {
log.error("Couldn't get latest GOC version {}", e);
return null;
}
return null;
}
}
......@@ -55,7 +55,7 @@ public class ProcessExecutorBash implements ProcessExecutor {
@Override
public List<String> executeProcessAndReturn(String command) throws IOException {
Process pr = Runtime.getRuntime().exec(command);
Process pr = Runtime.getRuntime().exec(new String[]{"bash","-c", command});
LOG.info("executing command: {}",command);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(pr.getInputStream()));
try {
......
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- edited with XMLSPY v2004 rel. 3 U (http://www.xmlspy.com) by Bob Dolin (HL7 CDA TC) -->
<xs:schema targetNamespace="urn:hl7-org:v3" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="urn:hl7-org:v3" xmlns:mif="urn:hl7-org:v3/mif" elementFormDefault="qualified">
<xs:include schemaLocation="POCD_MT000040_extended.xsd"/>
<xs:element name="ClinicalDocument" type="POCD_MT000040.ClinicalDocument"/>
</xs:schema>
<?xml version="1.0" encoding="utf-8"?>
<!--
*******************************************************************************
Schema for HL7 Clinical Document Architecture (CDA) R2 (2005)
Containing extensions for :
- POCD_MT000040.Material (HL7 Pharmacy CDA extensions)
- translated desinations for the coded elements (International Patient Summary (IPS) CDA extensions)
History:
2018.06.28 Giorgio Cangioli, first version based on the ELGA XML schema created by Tony Schaller, medshare GmbH, Switzerland
2022.02.25 Giorgio Cangioli, added part extension (pharma namespace)
*******************************************************************************
-->
<xs:schema xmlns:hl7v3="urn:hl7-org:v3" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:hl7-org:v3" elementFormDefault="qualified">
<xs:include schemaLocation="POCD_MT000040_Pharma.xsd"/>
<xs:element name="ClinicalDocument" type="hl7v3:POCD_MT000040.ClinicalDocument"/>
</xs:schema>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- edited with XMLSPY v2004 rel. 3 U (http://www.xmlspy.com) by Bob Dolin (HL7 CDA TC) -->
<xs:schema targetNamespace="urn:hl7-org:v3" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="urn:hl7-org:v3" xmlns:mif="urn:hl7-org:v3/mif" elementFormDefault="qualified">
<xs:include schemaLocation="POCD_MT000040.xsd"/>
<xs:element name="ClinicalDocument" type="POCD_MT000040.ClinicalDocument"/>
</xs:schema>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment